diff options
92 files changed, 6097 insertions, 5633 deletions
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane.xml new file mode 100644 index 0000000..ffe571f --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_airplane.xml @@ -0,0 +1,31 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M10.2,9.0"/> + <path + android:fill="#FF000000" + android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml new file mode 100644 index 0000000..22d0dcf --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml new file mode 100644 index 0000000..5057390 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml @@ -0,0 +1,31 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M19.0,10.0c0.0,-2.3 -1.15,-4.35 -2.9,-5.65l2.101,-2.1L17.4,1.4L15.1,3.7C14.15,3.3 13.1,3.0 12.0,3.0S9.85,3.3 8.9,3.75L6.6,1.45L5.8,2.3L7.9,4.4C6.15,5.65 5.0,7.7 5.0,10.0l0.0,1.0l14.0,0.0L19.0,10.0zM9.0,9.0C8.45,9.0 8.0,8.55 8.0,8.0s0.45,-1.0 1.0,-1.0s1.0,0.45 1.0,1.0S9.55,9.0 9.0,9.0zM15.0,9.0c-0.55,0.0 -1.0,-0.45 -1.0,-1.0s0.45,-1.0 1.0,-1.0s1.0,0.45 1.0,1.0S15.55,9.0 15.0,9.0z"/> + <path + android:fill="#FF000000" + android:pathData="M18.984,16.299C18.989,16.199 19.0,16.102 19.0,16.0l0.0,-2.301l2.517,2.268l0.837,-0.929L19.0,12.018L19.0,12.0L5.0,12.0l0.0,0.021l-0.013,-0.014l-3.364,3.031l0.836,0.929L5.0,13.678L5.0,16.0c0.0,0.11 0.012,0.218 0.017,0.327l-0.029,-0.032l-3.364,3.031l0.836,0.929l2.774,-2.499C6.019,20.762 8.757,23.0 12.0,23.0c3.236,0.0 5.971,-2.229 6.762,-5.227l2.755,2.481l0.837,-0.929l-3.365,-3.031L18.984,16.299z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast.xml new file mode 100644 index 0000000..6f2840b --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_cast.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_close.xml b/packages/SystemUI/res/drawable/ic_qs_close.xml new file mode 100644 index 0000000..c2c72c8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_close.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M19.0,6.4l-1.3999996,-1.4000001 -5.6000004,5.6000004 -5.6,-5.6000004 -1.4000001,1.4000001 5.6000004,5.6 -5.6000004,5.6000004 1.4000001,1.3999996 5.6,-5.6000004 5.6000004,5.6000004 1.3999996,-1.3999996 -5.6000004,-5.6000004z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml new file mode 100644 index 0000000..965e3c1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml new file mode 100644 index 0000000..7c92052 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_location.xml b/packages/SystemUI/res/drawable/ic_qs_location.xml new file mode 100644 index 0000000..e6e98a0 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_location.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M12.0,2.0C8.1,2.0 5.0,5.1 5.0,9.0c0.0,5.2 7.0,13.0 7.0,13.0s7.0,-7.8 7.0,-13.0C19.0,5.1 15.9,2.0 12.0,2.0zM12.0,11.5c-1.4,0.0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5c1.4,0.0 2.5,1.1 2.5,2.5S13.4,11.5 12.0,11.5z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml new file mode 100644 index 0000000..8323e89 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml new file mode 100644 index 0000000..84cd72a --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml new file mode 100644 index 0000000..fa6f20c --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml new file mode 100644 index 0000000..0665196 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml new file mode 100644 index 0000000..299a2ef --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation.xml b/packages/SystemUI/res/drawable/ic_qs_rotation.xml new file mode 100644 index 0000000..18c5922 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_rotation.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M16.5,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0C23.4,4.8 18.3,0.0 12.0,0.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.5,2.5zM10.2,1.7c-0.6,-0.6 -1.5,-0.6 -2.1,0.0L1.7,8.1c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.2,1.7zM14.8,21.2l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.8,21.2zM7.5,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5L0.1,13.0C0.6,19.2 5.7,24.0 12.0,24.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.5,21.5z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml new file mode 100644 index 0000000..1068f30 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_rotation_lock.xml @@ -0,0 +1,34 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M16.5,2.5c3.3,1.5 5.6,4.7 6.0,8.5L24.0,11.0C23.4,4.8 18.3,0.0 12.0,0.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.5,2.5zM7.5,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5L0.1,13.0C0.6,19.2 5.7,24.0 12.0,24.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.5,21.5z"/> + <path + android:pathData="M12.05,7.7c-1.104,0,-2,0.945,-2,2.05v0.5h4v-0.5C14.05,8.646,13.154,7.7,12.05,7.7z" + android:fill="#00000000"/> + <path + android:fill="#FF000000" + android:pathData="M15.05,10.25l0.0,-0.5c0.0,-1.656 -1.343,-3.0 -3.0,-3.0c-1.657,0.0 -2.995,1.344 -2.995,3.0l-0.005,0.5c-0.552,0.0 -1.0,0.448 -1.0,1.0l0.0,5.0c0.0,0.553 0.448,1.0 1.0,1.0l6.0,0.0c0.552,0.0 1.0,-0.447 1.0,-1.0l0.0,-5.0C16.05,10.698 15.602,10.25 15.05,10.25zM12.05,14.75c-0.552,0.0 -1.0,-0.447 -1.0,-1.0c0.0,-0.552 0.448,-1.0 1.0,-1.0s1.0,0.448 1.0,1.0C13.05,14.303 12.602,14.75 12.05,14.75zM14.05,10.25l-4.0,0.0l0.0,-0.5c0.0,-1.104 0.896,-2.05 2.0,-2.05c1.104,0.0 2.0,0.945 2.0,2.05L14.05,10.25z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml new file mode 100644 index 0000000..532a2ed --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_landscape.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M21.0,5.0L3.0,5.0C1.9,5.0 1.0,5.9 1.0,7.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l18.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,7.0C23.0,5.9 22.1,5.0 21.0,5.0zM19.0,17.0L5.0,17.0L5.0,7.0l14.0,0.0L19.0,17.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml new file mode 100644 index 0000000..496bb0e --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_rotation_locked_portrait.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M17.0,1.0L7.0,1.0C5.9,1.0 5.0,1.9 5.0,3.0l0.0,18.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L19.0,3.0C19.0,1.9 18.1,1.0 17.0,1.0zM17.0,19.0L7.0,19.0L7.0,5.0l10.0,0.0L17.0,19.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/ic_qs_zen.xml new file mode 100644 index 0000000..059c068 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_zen.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" > + <size + android:width="64dp" + android:height="64dp"/> + + <viewport + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> + + <path + android:fill="#FF000000" + android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/> +</vector> diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml index 355176c..c324976 100644 --- a/packages/SystemUI/res/layout/quick_settings_tile_media.xml +++ b/packages/SystemUI/res/drawable/qs_panel_background.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project +<!-- Copyright (C) 2014 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,12 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - style="@style/TextAppearance.QuickSettings.TileView.AllInOne" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" - android:text="@string/quick_settings_media_device_label" - android:singleLine="true" - /> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetLeft="@dimen/notification_side_padding" + android:insetRight="@dimen/notification_side_padding"> + <shape> + <solid android:color="@color/system_primary_color" /> + <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> + </shape> +</inset> diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml deleted file mode 100644 index 28d9625..0000000 --- a/packages/SystemUI/res/layout/flip_settings.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<com.android.systemui.statusbar.phone.QuickSettingsContainerView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/quick_settings_container" - android:padding="@dimen/notification_side_padding" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="#5f000000" - android:animateLayoutChanges="true" - android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml new file mode 100644 index 0000000..b24d4ad --- /dev/null +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/quick_settings_container" + android:paddingLeft="@dimen/notification_side_padding" + android:paddingRight="@dimen/notification_side_padding" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/qs_panel_background" > + <com.android.systemui.qs.QSPanel + android:id="@+id/quick_settings_panel" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> +</FrameLayout> diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml new file mode 100644 index 0000000..2df6d43 --- /dev/null +++ b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.android.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/system_secondary_color" > + + <com.android.systemui.qs.QSImageView + android:id="@android:id/button1" + android:layout_width="64dp" + android:layout_height="64dp" + android:layout_alignParentStart="true" + android:padding="@dimen/quick_settings_panel_padding" /> + + <Switch + android:id="@android:id/checkbox" + android:layout_width="wrap_content" + android:layout_height="64dp" + android:layout_alignParentEnd="true" + android:gravity="center" + android:padding="@dimen/quick_settings_panel_padding" /> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="64dp" + android:layout_toEndOf="@android:id/button1" + android:layout_toStartOf="@android:id/checkbox" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock" + android:gravity="center_vertical" + android:paddingStart="@dimen/quick_settings_panel_padding" + android:text="@string/zen_mode_title" /> + + <View + android:id="@android:id/custom" + android:layout_width="match_parent" + android:layout_height="2dp" + android:layout_below="@android:id/title" + android:background="#888" /> + + <ListView + android:id="@android:id/content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_above="@android:id/button2" + android:layout_below="@android:id/custom" + android:divider="#00000000" + android:dividerHeight="0px" /> + + <TextView + android:id="@android:id/button2" + style="@style/QSBorderless" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_alignParentEnd="true" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock" + android:padding="@dimen/quick_settings_panel_padding" + android:text="@string/quick_settings_more_settings" + android:textAllCaps="true" /> + +</com.android.systemui.qs.tiles.ZenModeDetail>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml new file mode 100644 index 0000000..a5c8903 --- /dev/null +++ b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" > + + <RadioButton + android:id="@android:id/checkbox" + android:layout_width="32dp" + android:layout_height="64dp" + android:layout_alignParentStart="true" + android:layout_marginStart="@dimen/quick_settings_panel_padding" + android:gravity="center" /> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="64dp" + android:layout_toEndOf="@android:id/checkbox" + android:layout_toStartOf="@android:id/button1" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock" + android:gravity="center_vertical" + android:maxLines="1" + android:text="@string/accessibility_back" /> + + <com.android.systemui.qs.QSImageView + android:id="@android:id/button1" + android:layout_width="64dp" + android:layout_height="64dp" + android:layout_alignParentEnd="true" + android:layout_marginEnd="48dp" + android:padding="@dimen/quick_settings_panel_padding" + android:paddingRight="0px" /> + + <com.android.systemui.qs.QSImageView + android:id="@android:id/button2" + android:layout_width="64dp" + android:layout_height="64dp" + android:layout_alignParentEnd="true" + android:padding="@dimen/quick_settings_panel_padding" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_tile.xml b/packages/SystemUI/res/layout/quick_settings_tile.xml deleted file mode 100644 index 911f6a2..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<com.android.systemui.statusbar.phone.QuickSettingsTileView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="@dimen/quick_settings_cell_height" - android:background="@drawable/qs_tile_background" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml b/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml deleted file mode 100644 index 493c704..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - style="@style/TextAppearance.QuickSettings.TileView.AllInOne" - android:id="@+id/alarm_textview" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:gravity="center" - android:drawableTop="@drawable/ic_qs_alarm_on" - /> diff --git a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml b/packages/SystemUI/res/layout/quick_settings_tile_basic.xml deleted file mode 100644 index 16bf49c..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="top" - android:orientation="vertical"> - <ImageView - android:id="@+id/image" - android:layout_marginTop="@dimen/qs_tile_margin_above_icon" - android:layout_marginBottom="@dimen/qs_tile_margin_below_icon" - android:layout_width="@dimen/qs_tile_icon_size" - android:layout_height="@dimen/qs_tile_icon_size" - android:layout_gravity="top|center_horizontal" - android:scaleType="centerInside" - /> - <TextView - style="@style/TextAppearance.QuickSettings.TileView" - android:id="@+id/text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top|center_horizontal" - android:gravity="top|center_horizontal" - /> -</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml deleted file mode 100644 index 1f39aef..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="top" - android:orientation="vertical"> - <com.android.systemui.BatteryMeterView - android:id="@+id/image" - android:layout_marginTop="@dimen/qs_tile_margin_above_icon" - android:layout_marginBottom="@dimen/qs_tile_margin_below_icon" - android:layout_width="22dp" - android:layout_height="32dp" - android:padding="3dp" - android:layout_gravity="top|center_horizontal" - systemui:frameColor="@color/qs_batterymeter_frame_color" - /> - <TextView - style="@style/TextAppearance.QuickSettings.TileView" - android:id="@+id/text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top|center_horizontal" - android:gravity="top|center_horizontal" - /> -</LinearLayout> diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml deleted file mode 100644 index 1a31efa5..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - style="@style/TextAppearance.QuickSettings.TileView.AllInOne" - android:id="@+id/ime_textview" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:gravity="center" - android:drawableTop="@drawable/ic_qs_ime" - android:text="@string/quick_settings_ime_label" - /> diff --git a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml b/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml deleted file mode 100644 index 4fa48eb..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="top" - android:orientation="vertical"> - <ImageView - android:id="@+id/image" - android:layout_marginTop="@dimen/qs_tile_margin_above_icon" - android:layout_marginBottom="@dimen/qs_cawarn_tile_margin_below_icon" - android:layout_width="@dimen/qs_tile_icon_size" - android:layout_height="@dimen/qs_tile_icon_size" - android:layout_gravity="top|center_horizontal" - android:scaleType="centerInside" - /> - <TextView - style="@style/TextAppearance.QuickSettings.CaCertWarning" - android:id="@+id/text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top|center_horizontal" - android:gravity="top|center_horizontal" - /> -</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml deleted file mode 100644 index 6bf31e0..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="top"> - <FrameLayout - android:id="@+id/rssi_images" - android:layout_marginTop="@dimen/qs_tile_margin_above_icon" - android:layout_marginBottom="@dimen/qs_tile_margin_below_icon" - android:layout_width="@dimen/qs_tile_icon_size" - android:layout_height="@dimen/qs_tile_icon_size" - android:layout_gravity="top|center_horizontal" - android:layout_centerHorizontal="true" - > - <ImageView - android:id="@+id/rssi_image" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerInParent="true" - /> - <ImageView - android:id="@+id/rssi_overlay_image" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerInParent="true" - /> - </FrameLayout> - <ImageView - android:id="@+id/activity_in" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_qs_signal_in" - android:layout_toRightOf="@id/rssi_images" - android:layout_alignBottom="@id/rssi_images" - /> - <ImageView - android:id="@+id/activity_out" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_qs_signal_out" - android:layout_toRightOf="@id/rssi_images" - android:layout_alignBottom="@id/rssi_images" - /> - <TextView - style="@style/TextAppearance.QuickSettings.TileView" - android:id="@+id/rssi_textview" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|center_horizontal" - android:gravity="top|center_horizontal" - android:text="@string/quick_settings_rssi_label" - android:layout_centerHorizontal="true" - android:layout_below="@id/rssi_images" - android:textAllCaps="@bool/quick_settings_rssi_tile_capitalization" - /> -</RelativeLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml deleted file mode 100644 index 80fc685..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <ImageView - android:id="@+id/user_imageview" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:src="@drawable/ic_qs_default_user" - android:scaleType="centerCrop" - /> - <TextView - style="@style/TextAppearance.QuickSettings.TileView.User" - android:id="@+id/user_textview" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|bottom" - android:gravity="center" - android:text="@string/quick_settings_user_label" - /> -</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml deleted file mode 100644 index e61c595..0000000 --- a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="top"> - <ImageView - android:id="@+id/image" - android:layout_marginTop="@dimen/qs_tile_margin_above_icon" - android:layout_marginBottom="@dimen/qs_tile_margin_below_icon" - android:layout_width="@dimen/qs_tile_icon_size" - android:layout_height="@dimen/qs_tile_icon_size" - android:layout_gravity="top|center_horizontal" - android:layout_centerHorizontal="true" - android:scaleType="centerInside" - /> - <ImageView - android:id="@+id/activity_in" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_qs_wifi_in" - android:layout_toRightOf="@id/image" - android:layout_alignBottom="@id/image" - /> - <ImageView - android:id="@+id/activity_out" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_qs_wifi_out" - android:layout_toRightOf="@id/image" - android:layout_alignBottom="@id/image" - /> - <TextView - style="@style/TextAppearance.QuickSettings.TileView" - android:id="@+id/text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top|center_horizontal" - android:gravity="top|center_horizontal" - android:layout_centerHorizontal="true" - android:layout_below="@id/image" - /> -</RelativeLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index f045da4..2ec9935 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -67,7 +67,7 @@ android:layout_height="wrap_content" android:orientation="vertical"> <include - layout="@layout/flip_settings" + layout="@layout/qs_panel" android:layout_marginTop="@dimen/status_bar_header_height_expanded" android:layout_width="match_parent" android:layout_height="wrap_content"/> diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index 7223773..5755029 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -25,7 +25,7 @@ <integer name="status_bar_recents_bg_gradient_degrees">90</integer> <!-- The number of columns in the QuickSettings --> - <integer name="quick_settings_num_columns">6</integer> + <integer name="quick_settings_num_columns">4</integer> <!-- The maximum number of rows in the QuickSettings --> <integer name="quick_settings_max_rows">2</integer> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index fe2224e..6dea81f 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -21,7 +21,7 @@ for different hardware and product builds. --> <resources> <!-- The number of columns in the QuickSettings --> - <integer name="quick_settings_num_columns">3</integer> + <integer name="quick_settings_num_columns">4</integer> <!-- The maximum number of rows in the QuickSettings --> <integer name="quick_settings_max_rows">4</integer> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index c1a4e26..7de1bd0 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -36,6 +36,14 @@ <color name="batterymeter_charge_color">#FFFFFFFF</color> <color name="batterymeter_bolt_color">#FFFFFFFF</color> <color name="qs_batterymeter_frame_color">#FF404040</color> + <color name="system_primary_color">#ff263238</color> + <color name="system_secondary_color">#ff384248</color> + <color name="system_accent_color">#ff7fcac3</color> + <color name="system_error_color">#fff0592b</color> + <color name="quick_settings_tile_icon_enabled">#ffffffff</color> + <color name="quick_settings_tile_icon_disabled">#ffcccccc</color> + <color name="quick_settings_tile_divider">#ff888888</color> + <color name="quick_settings_tile_text">#FFFFFFFF</color> <color name="status_bar_clock_color">#FFFFFFFF</color> <drawable name="notification_item_background_color">#ff111111</drawable> <drawable name="notification_item_background_color_pressed">#ff454545</drawable> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ab34030..79612e0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -271,6 +271,10 @@ <dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen> <dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen> + <dimen name="quick_settings_panel_padding">16dp</dimen> + <dimen name="quick_settings_tile_icon_outline">2dp</dimen> + <dimen name="quick_settings_tile_text_size">12sp</dimen> + <dimen name="quick_settings_tile_divider_height">1dp</dimen> <dimen name="notifications_top_padding">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3d3cdf6..a50a0ac 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -503,9 +503,15 @@ <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] --> <string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string> <!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] --> - <string name="quick_settings_inversion_label">Color inversion mode</string> + <string name="quick_settings_inversion_label">Invert colors</string> <!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] --> <string name="quick_settings_color_space_label">Color correction mode</string> + <!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] --> + <string name="quick_settings_more_settings">More settings</string> + <!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] --> + <string name="quick_settings_tethering_label">Tethering</string> + <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] --> + <string name="quick_settings_hotspot_label">Hotspot</string> <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] --> <string name="recents_empty_message">RECENTS</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 4f52870..1273e74 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -180,4 +180,16 @@ <style name="StatusBarHeader"> <item name="android:layout_width">match_parent</item> </style> + + <style name="QSWhiteTheme" parent="@android:style/Theme.DeviceDefault"> + <item name="android:colorControlNormal">#ffffffff</item> + <item name="android:colorControlActivated">#ffffffff</item> + </style> + + <style name="QSAccentTheme" parent="@android:style/Theme.DeviceDefault"> + <item name="android:colorControlNormal">@color/system_accent_color</item> + <item name="android:colorControlActivated">@color/system_accent_color</item> + </style> + + <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" /> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java new file mode 100644 index 0000000..16ee3b0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.view.View; + +/** Helper for view-level circular clip animations. **/ +public class CircularClipper { + + private final View mTarget; + + private ValueAnimator mAnimator; + + public CircularClipper(View target) { + mTarget = target; + } + + public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) { + if (mAnimator != null) { + mAnimator.cancel(); + } + final int w = mTarget.getWidth() - x; + final int h = mTarget.getHeight() - y; + int r = (int) Math.ceil(Math.sqrt(x * x + y * y)); + r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + y * y))); + r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + h * h))); + r = (int) Math.max(r, Math.ceil(Math.sqrt(x * x + h * h))); + + mAnimator = mTarget.createRevealAnimator(x, y, 0, r); + mAnimator.removeAllListeners(); + if (listener != null) { + mAnimator.addListener(listener); + } + if (in) { + mAnimator.addListener(mVisibleOnStart); + mAnimator.start(); + } else { + mAnimator.addListener(mGoneOnEnd); + mAnimator.reverse(); + } + } + + private final AnimatorListenerAdapter mVisibleOnStart = new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mTarget.setVisibility(View.VISIBLE); + } + }; + + private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mTarget.setVisibility(View.GONE); + }; + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java new file mode 100644 index 0000000..05c8ee3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; + +/** Canvas that forwards calls to another canvas. Can be subclassed to transform drawing calls. + * Temporary solution to runtime modification of a single drawable shape into two + * enabled & disabled versions. See QSImageView. **/ +public class FilterCanvas extends Canvas { + private final Canvas mCanvas; + + public FilterCanvas(Canvas c) { + mCanvas = c; + } + + @Override + public void drawPath(Path path, Paint paint) { + mCanvas.drawPath(path, paint); + } + + @Override + public int getSaveCount() { + return mCanvas.getSaveCount(); + } + + @Override + public int save() { + return mCanvas.save(); + } + + @Override + public void translate(float dx, float dy) { + mCanvas.translate(dx, dy); + } + + @Override + public boolean clipRect(int left, int top, int right, int bottom) { + return mCanvas.clipRect(left, top, right, bottom); + } + + @Override + public boolean clipRect(Rect rect) { + return mCanvas.clipRect(rect); + } + + @Override + public void concat(Matrix matrix) { + mCanvas.concat(matrix); + } + + @Override + public void restoreToCount(int saveCount) { + mCanvas.restoreToCount(saveCount); + } + + @Override + public void drawRect(Rect r, Paint paint) { + mCanvas.drawRect(r, paint); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java new file mode 100644 index 0000000..1e15b9f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings.Global; + +import com.android.systemui.statusbar.policy.Disposable; + +/** Helper for managing a global setting. **/ +public abstract class GlobalSetting extends ContentObserver implements Disposable { + private final Context mContext; + private final String mSettingName; + + protected abstract void handleValueChanged(int value); + + public GlobalSetting(Context context, Handler handler, String settingName) { + super(handler); + mContext = context; + mSettingName = settingName; + mContext.getContentResolver().registerContentObserver( + Global.getUriFor(mSettingName), false, this); + } + + public int getValue() { + return Global.getInt(mContext.getContentResolver(), mSettingName, 0); + } + + public void setValue(int value) { + Global.putInt(mContext.getContentResolver(), mSettingName, value); + } + + @Override + public void dispose() { + mContext.getContentResolver().unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + handleValueChanged(getValue()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java new file mode 100644 index 0000000..ed67560 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.VectorDrawable; +import android.util.AttributeSet; +import android.widget.ImageView; + +import com.android.systemui.R; + +/** ImageView that performs runtime modification of vector drawables (using FilterCanvas). **/ +public class QSImageView extends ImageView { + + private final int mOutlineWidth; + private final int mColorEnabled; + private final int mColorDisabled; + private FilterCanvas mFilterCanvas; + private Canvas mCanvas; + private boolean mEnabledVersion = true; + private boolean mFilter; + + public QSImageView(Context context) { + this(context, null); + } + + public QSImageView(Context context, AttributeSet attrs) { + super(context, attrs); + final Resources res = context.getResources(); + mOutlineWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tile_icon_outline); + mColorEnabled = res.getColor(R.color.quick_settings_tile_icon_enabled); + mColorDisabled = res.getColor(R.color.quick_settings_tile_icon_disabled); + } + + public void setEnabledVersion(boolean enabledVersion) { + mEnabledVersion = enabledVersion; + invalidate(); + } + + @Override + public void setImageDrawable(Drawable drawable) { + mFilter = drawable instanceof VectorDrawable; + super.setImageDrawable(drawable); + } + + @Override + public void setImageResource(int resId) { + setImageDrawable(mContext.getDrawable(resId)); + } + + @Override + public void draw(Canvas canvas) { + if (mFilter) { + if (canvas != mCanvas) { + mCanvas = canvas; + mFilterCanvas = new QSFilterCanvas(canvas); + } + super.draw(mFilterCanvas); + } else { + super.draw(canvas); + } + } + + private class QSFilterCanvas extends FilterCanvas { + public QSFilterCanvas(Canvas c) { + super(c); + } + + @Override + public void drawPath(Path path, Paint paint) { + if (mEnabledVersion) { + paint.setColor(mColorEnabled); + } else { + paint.setStyle(Style.STROKE); + paint.setStrokeJoin(Paint.Join.ROUND); + paint.setColor(mColorDisabled); + paint.setStrokeWidth(mOutlineWidth); + } + super.drawPath(path, paint); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java new file mode 100644 index 0000000..afb5483 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.android.systemui.R; + +import java.util.ArrayList; + +/** View that represents the quick settings tile panel. **/ +public class QSPanel extends ViewGroup { + private static final float TILE_ASPECT = 1.4f; + private static final float LARGE_TILE_FACTOR = 1.1f; + + private final Context mContext; + private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>(); + private final FrameLayout mDetail; + private final CircularClipper mClipper; + private final H mHandler = new H(); + + private int mColumns; + private int mCellWidth; + private int mCellHeight; + private int mLargeCellWidth; + private int mLargeCellHeight; + + private TileRecord mDetailRecord; + + public QSPanel(Context context) { + this(context, null); + } + + public QSPanel(Context context, AttributeSet attrs) { + super(context, attrs); + mContext = context; + + mDetail = new FrameLayout(mContext); + mDetail.setVisibility(GONE); + mDetail.setClickable(true); + addView(mDetail); + mClipper = new CircularClipper(mDetail); + updateResources(); + } + + public void updateResources() { + final int columns = Math.max(1, + mContext.getResources().getInteger(R.integer.quick_settings_num_columns)); + if (mColumns != columns) { + mColumns = columns; + postInvalidate(); + } + } + + public void setExpanded(boolean expanded) { + if (!expanded) { + showDetail(false /*show*/, mDetailRecord); + } + for (TileRecord r : mRecords) { + r.tile.setShown(expanded); + } + } + + private void showDetail(boolean show, TileRecord r) { + mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget(); + } + + private void setTileVisibility(View v, boolean visible) { + mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visible ? 1 : 0, 0, v).sendToTarget(); + } + + private void handleSetTileVisibility(View v, boolean visible) { + v.setVisibility(visible ? VISIBLE : GONE); + } + + public void addTile(final QSTile<?> tile) { + final TileRecord r = new TileRecord(); + r.tile = tile; + r.tileView = tile.createTileView(mContext); + r.tileView.setVisibility(View.GONE); + r.tile.setCallback(new QSTile.Callback() { + @Override + public void onStateChanged(QSTile.State state) { + setTileVisibility(r.tileView, state.visible); + r.tileView.onStateChanged(state); + } + @Override + public void onShowDetail(boolean show) { + QSPanel.this.showDetail(show, r); + } + }); + final View.OnClickListener click = new View.OnClickListener() { + @Override + public void onClick(View v) { + r.tile.click(); + } + }; + final View.OnClickListener clickSecondary = new View.OnClickListener() { + @Override + public void onClick(View v) { + r.tile.secondaryClick(); + } + }; + r.tileView.init(click, clickSecondary); + mRecords.add(r); + + addView(r.tileView); + } + + private void handleShowDetail(TileRecord r, boolean show) { + AnimatorListener listener = null; + if (show) { + if (mDetailRecord != null) return; + final View detail = r.tile.createDetailView(mContext, mDetail); + if (detail == null) return; + mDetailRecord = r; + mDetail.removeAllViews(); + mDetail.bringToFront(); + mDetail.addView(detail); + } else { + if (mDetailRecord == null) return; + listener = mTeardownDetailWhenDone; + } + int x = r.tileView.getLeft() + r.tileView.getWidth() / 2; + int y = r.tileView.getTop() + r.tileView.getHeight() / 2; + mClipper.animateCircularClip(x, y, show, listener); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int width = MeasureSpec.getSize(widthMeasureSpec); + mCellWidth = width / mColumns; + mCellHeight = (int)(mCellWidth / TILE_ASPECT); + mLargeCellWidth = (int)(mCellWidth * LARGE_TILE_FACTOR); + mLargeCellHeight = (int)(mCellHeight * LARGE_TILE_FACTOR); + int r = 0; + int c = 0; + int rows = 0; + for (TileRecord record : mRecords) { + if (record.tileView.getVisibility() == GONE) continue; + record.row = r; + record.col = c; + rows = r + 1; + c++; + if (c == mColumns /*end of normal column*/ || r == 0 && c == 2 /*end of 1st column*/) { + c = 0; + r++; + } + } + + for (TileRecord record : mRecords) { + if (record.tileView.getVisibility() == GONE) continue; + record.tileView.setDual(record.row == 0); + final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth; + final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight; + record.tileView.measure(exactly(cw), exactly(ch)); + } + final int actualHeight = rows == 0 ? 0 : getRowTop(rows); + mDetail.measure(exactly(width), exactly(actualHeight)); + setMeasuredDimension(width, actualHeight); + } + + private static int exactly(int size) { + return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int w = mCellWidth * mColumns; + for (TileRecord record : mRecords) { + if (record.tileView.getVisibility() == GONE) continue; + final int cols = getColumnCount(record.row); + final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth; + final int extra = (w - cw * cols) / (cols + 1); + final int left = record.col * cw + (record.col + 1) * extra; + final int top = getRowTop(record.row); + record.tileView.layout(left, top, + left + record.tileView.getMeasuredWidth(), + top + record.tileView.getMeasuredHeight()); + } + mDetail.layout(0, 0, mDetail.getMeasuredWidth(), mDetail.getMeasuredHeight()); + } + + private int getRowTop(int row) { + if (row <= 0) return 0; + return mLargeCellHeight + (row - 1) * mCellHeight; + } + + private int getColumnCount(int row) { + int cols = 0; + for (TileRecord record : mRecords) { + if (record.tileView.getVisibility() == GONE) continue; + if (record.row == row) cols++; + } + return cols; + } + + private class H extends Handler { + private static final int SHOW_DETAIL = 1; + private static final int SET_TILE_VISIBILITY = 2; + @Override + public void handleMessage(Message msg) { + if (msg.what == SHOW_DETAIL) { + handleShowDetail((TileRecord)msg.obj, msg.arg1 != 0); + } else if (msg.what == SET_TILE_VISIBILITY) { + handleSetTileVisibility((View)msg.obj, msg.arg1 != 0); + } + } + } + + private static final class TileRecord { + QSTile<?> tile; + QSTileView tileView; + int row; + int col; + } + + private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + mDetail.removeAllViews(); + mDetailRecord = null; + }; + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java new file mode 100644 index 0000000..39c8515 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.VectorDrawable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import com.android.systemui.qs.QSTile.State; +import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.CastController; +import com.android.systemui.statusbar.policy.Disposable; +import com.android.systemui.statusbar.policy.LocationController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.TetheringController; +import com.android.systemui.statusbar.policy.ZenModeController; + +import java.util.List; +import java.util.Objects; + +/** + * Base quick-settings tile, extend this to create a new tile. + * + * State management done on a looper provided by the host. Tiles should update state in + * handleUpdateState. Callbacks affecting state should use refreshState to trigger another + * state update pass on tile looper. + */ +public abstract class QSTile<TState extends State> implements Disposable { + private final String TAG = "QSTile." + getClass().getSimpleName(); + + protected final Host mHost; + protected final Context mContext; + protected final H mHandler; + + private Callback mCallback; + protected final TState mState = newTileState(); + private final TState mTmpState = newTileState(); + + abstract protected TState newTileState(); + abstract protected void handleClick(); + abstract protected void handleUpdateState(TState state, Object arg); + + protected QSTile(Host host) { + mHost = host; + mContext = host.getContext(); + mHandler = new H(host.getLooper()); + } + + public Host getHost() { + return mHost; + } + + public QSTileView createTileView(Context context) { + return new QSTileView(context); + } + + public View createDetailView(Context context, ViewGroup root) { + return null; // optional + } + + // safe to call from any thread + + public void setCallback(Callback callback) { + mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget(); + } + + public void click() { + mHandler.sendEmptyMessage(H.CLICK); + } + + public void secondaryClick() { + mHandler.sendEmptyMessage(H.SECONDARY_CLICK); + } + + public void showDetail(boolean show) { + mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget(); + } + + protected final void refreshState() { + refreshState(null); + } + + protected final void refreshState(Object arg) { + mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget(); + } + + public void userSwitch(int newUserId) { + mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget(); + } + + public void setShown(boolean shown) { + mHandler.obtainMessage(H.SHOWN, shown ? 1 : 0, 0).sendToTarget(); + } + + // call only on tile worker looper + + private void handleSetCallback(Callback callback) { + mCallback = callback; + handleRefreshState(null); + } + + protected void handleSecondaryClick() { + // optional + } + + protected void handleShown(boolean shown) { + // optional, discouraged + } + + protected void handleRefreshState(Object arg) { + handleUpdateState(mTmpState, arg); + final boolean changed = mTmpState.copyTo(mState); + if (changed) { + handleStateChanged(); + } + } + + private void handleStateChanged() { + if (mCallback != null) { + mCallback.onStateChanged(mState); + } + } + + private void handleShowDetail(boolean show) { + if (mCallback != null) { + mCallback.onShowDetail(show); + } + } + + protected void handleUserSwitch(int newUserId) { + handleRefreshState(null); + } + + protected final class H extends Handler { + private static final int SET_CALLBACK = 1; + private static final int CLICK = 2; + private static final int SECONDARY_CLICK = 3; + private static final int REFRESH_STATE = 4; + private static final int SHOW_DETAIL = 5; + private static final int USER_SWITCH = 6; + private static final int SHOWN = 7; + + private H(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + String name = null; + try { + if (msg.what == SET_CALLBACK) { + name = "handleSetCallback"; + handleSetCallback((QSTile.Callback)msg.obj); + } else if (msg.what == CLICK) { + name = "handleClick"; + handleClick(); + } else if (msg.what == SECONDARY_CLICK) { + name = "handleSecondaryClick"; + handleSecondaryClick(); + } else if (msg.what == REFRESH_STATE) { + name = "handleRefreshState"; + handleRefreshState(msg.obj); + } else if (msg.what == SHOW_DETAIL) { + name = "handleShowDetail"; + handleShowDetail(msg.arg1 != 0); + } else if (msg.what == USER_SWITCH) { + name = "handleUserSwitch"; + handleUserSwitch(msg.arg1); + } else if (msg.what == SHOWN) { + name = "handleShown"; + handleShown(msg.arg1 != 0); + } + } catch (Throwable t) { + final String error = "Error in " + name; + Log.w(TAG, error, t); + mHost.warn(error, t); + } + } + } + + public interface Callback { + void onStateChanged(State state); + void onShowDetail(boolean show); + } + + public interface Host { + void startSettingsActivity(Intent intent); + void warn(String message, Throwable t); + void collapsePanels(); + Looper getLooper(); + Context getContext(); + VectorDrawable getVectorDrawable(int resId); + BluetoothController getBluetoothController(); + LocationController getLocationController(); + RotationLockController getRotationLockController(); + List<QSTile<?>> getTiles(); + NetworkController getNetworkController(); + ZenModeController getZenModeController(); + TetheringController getTetheringController(); + CastController getCastController(); + } + + public static class State { + public boolean visible; + public int iconId; + public VectorDrawable icon; + public String label; + public String contentDescription; + + public boolean copyTo(State other) { + if (other == null) throw new IllegalArgumentException(); + if (!other.getClass().equals(getClass())) throw new IllegalArgumentException(); + final boolean changed = other.visible != visible + || other.iconId != iconId + || !Objects.equals(other.icon, icon) + || !Objects.equals(other.label, label) + || !Objects.equals(other.contentDescription, contentDescription); + other.visible = visible; + other.iconId = iconId; + other.icon = icon; + other.label = label; + other.contentDescription = contentDescription; + return changed; + } + + @Override + public String toString() { + return toStringBuilder().toString(); + } + + protected StringBuilder toStringBuilder() { + final StringBuilder sb = new StringBuilder( getClass().getSimpleName()).append('['); + sb.append("visible=").append(visible); + sb.append(",iconId=").append(iconId); + sb.append(",icon=").append(icon); + sb.append(",label=").append(label); + sb.append(",contentDescription=").append(contentDescription); + return sb.append(']'); + } + } + + public static class BooleanState extends State { + public boolean value; + + @Override + public boolean copyTo(State other) { + final BooleanState o = (BooleanState) other; + final boolean changed = super.copyTo(other) || o.value != value; + o.value = value; + return changed; + } + + @Override + protected StringBuilder toStringBuilder() { + final StringBuilder rt = super.toStringBuilder(); + rt.insert(rt.length() - 1, ",value=" + value); + return rt; + } + } + + public static final class SignalState extends State { + public boolean enabled; + public boolean connected; + public boolean activityIn; + public boolean activityOut; + public int overlayIconId; + + @Override + public boolean copyTo(State other) { + final SignalState o = (SignalState) other; + final boolean changed = o.enabled != enabled + || o.connected != connected || o.activityIn != activityIn + || o.activityOut != activityOut + || o.overlayIconId != overlayIconId; + o.enabled = enabled; + o.connected = connected; + o.activityIn = activityIn; + o.activityOut = activityOut; + o.overlayIconId = overlayIconId; + return super.copyTo(other) || changed; + } + + @Override + protected StringBuilder toStringBuilder() { + final StringBuilder rt = super.toStringBuilder(); + rt.insert(rt.length() - 1, ",enabled=" + enabled); + rt.insert(rt.length() - 1, ",connected=" + connected); + rt.insert(rt.length() - 1, ",activityIn=" + activityIn); + rt.insert(rt.length() - 1, ",activityOut=" + activityOut); + rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId); + return rt; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java new file mode 100644 index 0000000..17a95fb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView.ScaleType; +import android.widget.TextView; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile.State; + +/** View that represents a standard quick settings tile. **/ +public class QSTileView extends ViewGroup { + private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed", + Typeface.NORMAL); + private static final int VERTICAL_PADDING_FACTOR = 8; // internal padding 1/8 the cell height + + protected final Context mContext; + private final View mIcon; + private final View mDivider; + private final TextView mLabel; + private final H mHandler = new H(); + + private boolean mDual; + private OnClickListener mClickPrimary; + private OnClickListener mClickSecondary; + + public QSTileView(Context context) { + super(context); + + mContext = context; + final Resources res = context.getResources(); + mLabel = new TextView(mContext); + mLabel.setId(android.R.id.title); + mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text)); + mLabel.setGravity(Gravity.CENTER); + mLabel.setTypeface(CONDENSED); + mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, + res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size)); + addView(mLabel); + setClipChildren(false); + + mIcon = createIcon(); + addView(mIcon); + + mDivider = new View(mContext); + mDivider.setBackgroundColor(res.getColor(R.color.quick_settings_tile_divider)); + final int dh = res.getDimensionPixelSize(R.dimen.quick_settings_tile_divider_height); + mDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dh)); + addView(mDivider); + + setClickable(true); + setBackground(getSelectableBackground()); + } + + public void setDual(boolean dual) { + mDual = dual; + if (mDual) { + setOnClickListener(mClickPrimary); + mLabel.setClickable(true); + mLabel.setOnClickListener(mClickSecondary); + } else { + mLabel.setClickable(false); + setOnClickListener(mClickPrimary); + } + mDivider.setVisibility(dual ? VISIBLE : GONE); + postInvalidate(); + } + + public void init(OnClickListener clickPrimary, OnClickListener clickSecondary) { + mClickPrimary = clickPrimary; + mClickSecondary = clickSecondary; + } + + protected View createIcon() { + QSImageView icon = new QSImageView(mContext); + icon.setId(android.R.id.icon); + icon.setScaleType(ScaleType.CENTER_INSIDE); + return icon; + } + + private Drawable getSelectableBackground() { + final int[] attrs = new int[] { android.R.attr.selectableItemBackground}; + final TypedArray ta = mContext.obtainStyledAttributes(attrs); + final Drawable d = ta.getDrawable(0); + ta.recycle(); + return d; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int w = MeasureSpec.getSize(widthMeasureSpec); + final int h = MeasureSpec.getSize(heightMeasureSpec); + final int p = h / VERTICAL_PADDING_FACTOR; + final int iconSpec = exactly((int)mLabel.getTextSize() * 2); + mIcon.measure(iconSpec, iconSpec); + mLabel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST)); + mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2)); + if (mDual) { + mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height)); + } + setMeasuredDimension(w, h); + } + + private static int exactly(int size) { + return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int w = getMeasuredWidth(); + final int h = getMeasuredHeight(); + final int p = h / VERTICAL_PADDING_FACTOR; + final int contentHeight = p + mIcon.getMeasuredHeight() + mLabel.getMeasuredHeight() + + (mDual ? (p + mDivider.getMeasuredHeight()) : 0); + + int top = (h - contentHeight) / 2 + p; + final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2; + layout(mIcon, iconLeft, top); + top = mIcon.getBottom(); + if (mDual) { + top += p; + layout(mDivider, 0, top); + top = mDivider.getBottom(); + } + layout(mLabel, 0, top); + } + + private static void layout(View child, int left, int top) { + child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); + } + + protected void handleStateChanged(QSTile.State state) { + if (mIcon instanceof QSImageView) { + QSImageView qsiv = (QSImageView) mIcon; + if (state.icon != null) { + qsiv.setImageDrawable(state.icon); + } else if (state.iconId > 0) { + qsiv.setImageResource(state.iconId); + } + if (state.icon != null && state instanceof QSTile.BooleanState) { + qsiv.setEnabledVersion(((QSTile.BooleanState)state).value); + } + } + mLabel.setText(state.label); + setContentDescription(state.contentDescription); + } + + public void onStateChanged(QSTile.State state) { + mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget(); + } + + private class H extends Handler { + private static final int STATE_CHANGED = 1; + public H() { + super(Looper.getMainLooper()); + } + @Override + public void handleMessage(Message msg) { + if (msg.what == STATE_CHANGED) { + handleStateChanged((State) msg.obj); + } + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java new file mode 100644 index 0000000..4debaa9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings.Secure; + +import com.android.systemui.statusbar.policy.Disposable; + +/** Helper for managing a secure setting. **/ +public abstract class SecureSetting extends ContentObserver implements Disposable { + private final Context mContext; + private final String mSettingName; + + protected abstract void handleValueChanged(int value); + + public SecureSetting(Context context, Handler handler, String settingName) { + super(handler); + mContext = context; + mSettingName = settingName; + rebindForCurrentUser(); + } + + public void rebindForCurrentUser() { + mContext.getContentResolver().registerContentObserver( + Secure.getUriFor(mSettingName), false, this); + } + + public int getValue() { + return Secure.getInt(mContext.getContentResolver(), mSettingName, 0); + } + + public void setValue(int value) { + Secure.putInt(mContext.getContentResolver(), mSettingName, value); + } + + @Override + public void dispose() { + mContext.getContentResolver().unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + handleValueChanged(getValue()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java new file mode 100644 index 0000000..7b6c544 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile.SignalState; + +/** View that represents a custom quick settings tile for displaying signal info (wifi/cell). **/ +public final class SignalTileView extends QSTileView { + private static final long DEFAULT_DURATION = new ValueAnimator().getDuration(); + private static final long SHORT_DURATION = DEFAULT_DURATION / 3; + + private FrameLayout mIconFrame; + private ImageView mSignal; + private ImageView mOverlay; + private ImageView mIn; + private ImageView mOut; + + public SignalTileView(Context context) { + super(context); + + mIn = new ImageView(context); + mIn.setImageResource(R.drawable.ic_qs_signal_in); + addView(mIn); + + mOut = new ImageView(context); + mOut.setImageResource(R.drawable.ic_qs_signal_out); + addView(mOut); + } + + @Override + protected View createIcon() { + mIconFrame = new FrameLayout(mContext); + mSignal = new ImageView(mContext); + mIconFrame.addView(mSignal); + mOverlay = new ImageView(mContext); + mIconFrame.addView(mOverlay); + return mIconFrame; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int hs = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.EXACTLY); + int ws = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.AT_MOST); + mIn.measure(ws, hs); + mOut.measure(ws, hs); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + layoutIndicator(mIn); + layoutIndicator(mOut); + } + + private void layoutIndicator(View indicator) { + indicator.layout( + mIconFrame.getRight(), + mIconFrame.getBottom() - indicator.getMeasuredHeight(), + mIconFrame.getRight() + indicator.getMeasuredWidth(), + mIconFrame.getBottom()); + } + + @Override + protected void handleStateChanged(QSTile.State state) { + super.handleStateChanged(state); + final SignalState s = (SignalState) state; + mSignal.setImageDrawable(null); // force refresh + mSignal.setImageResource(s.iconId); + if (s.overlayIconId > 0) { + mOverlay.setVisibility(VISIBLE); + mOverlay.setImageDrawable(null); // force refresh + mOverlay.setImageResource(s.overlayIconId); + } else { + mOverlay.setVisibility(GONE); + } + setVisibility(mIn, s.activityIn); + setVisibility(mOut, s.activityOut); + } + + private void setVisibility(View view, boolean visible) { + final float newAlpha = visible ? 1 : 0; + if (view.getAlpha() != newAlpha) { + view.animate() + .setDuration(visible ? SHORT_DURATION : DEFAULT_DURATION) + .alpha(newAlpha) + .withLayer() + .start(); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java new file mode 100644 index 0000000..5fe8422 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.provider.Settings.Global; + +import com.android.systemui.R; +import com.android.systemui.qs.GlobalSetting; +import com.android.systemui.qs.QSTile; + +/** Quick settings tile: Airplane mode **/ +public class AirplaneModeTile extends QSTile<QSTile.BooleanState> { + private final GlobalSetting mSetting; + + public AirplaneModeTile(Host host) { + super(host); + + mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) { + @Override + protected void handleValueChanged(int value) { + handleRefreshState(value); + } + }; + + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); + mContext.registerReceiver(mReceiver, filter); + refreshState(); + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + @Override + public void handleClick() { + setEnabled(!mState.value); + } + + private void setEnabled(boolean enabled) { + mSetting.setValue(enabled ? 1 : 0); + final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enabled); + mContext.sendBroadcast(intent); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue(); + final boolean airplaneMode = value != 0; + state.value = airplaneMode; + state.visible = true; + state.label = mContext.getString(R.string.quick_settings_airplane_mode_label); + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_airplane); + if (airplaneMode) { + state.iconId = R.drawable.ic_qs_airplane_on; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_airplane, + mContext.getString(R.string.accessibility_desc_on)); + } else { + state.iconId = R.drawable.ic_qs_airplane_off; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_airplane, + mContext.getString(R.string.accessibility_desc_off)); + } + } + + public void dispose() { + mSetting.dispose(); + mContext.unregisterReceiver(mReceiver); + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) { + refreshState(); + } + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java new file mode 100644 index 0000000..60a6047 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback; +import android.content.Intent; +import android.provider.Settings; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.BluetoothController; + +/** Quick settings tile: Bluetooth **/ +public class BluetoothTile extends QSTile<QSTile.BooleanState> { + private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS); + + private final BluetoothController mController; + + public BluetoothTile(Host host) { + super(host); + mController = host.getBluetoothController(); + mController.addStateChangedCallback(mCallback); + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + @Override + public void dispose() { + mController.removeStateChangedCallback(mCallback); + } + + @Override + protected void handleClick() { + final boolean isEnabled = (Boolean)mState.value; + mController.setBluetoothEnabled(!isEnabled); + } + + @Override + protected void handleSecondaryClick() { + mHost.startSettingsActivity(BLUETOOTH_SETTINGS); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final boolean supported = mController.isBluetoothSupported(); + final boolean enabled = mController.isBluetoothEnabled(); + final boolean connected = mController.isBluetoothConnected(); + state.visible = supported; + state.value = enabled; + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bluetooth); + final String stateContentDescription; + if (enabled) { + if (connected) { + state.iconId = R.drawable.ic_qs_bluetooth_on; + stateContentDescription = mContext.getString(R.string.accessibility_desc_connected); + } else { + state.iconId = R.drawable.ic_qs_bluetooth_not_connected; + stateContentDescription = mContext.getString(R.string.accessibility_desc_on); + } + state.label = mContext.getString(R.string.quick_settings_bluetooth_label); + } else { + state.iconId = R.drawable.ic_qs_bluetooth_off; + state.label = mContext.getString(R.string.quick_settings_bluetooth_off_label); + stateContentDescription = mContext.getString(R.string.accessibility_desc_off); + } + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_bluetooth, stateContentDescription); + } + + private final BluetoothStateChangeCallback mCallback = new BluetoothStateChangeCallback() { + @Override + public void onBluetoothStateChange(boolean on) { + refreshState(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java new file mode 100644 index 0000000..1a7b880 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.app.ActivityManagerNative; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.os.RemoteException; +import android.provider.Settings.Global; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; + +import com.android.systemui.R; +import com.android.systemui.qs.GlobalSetting; +import com.android.systemui.qs.QSTile; + +/** Quick settings tile: Bug report **/ +public class BugreportTile extends QSTile<QSTile.State> { + + private final GlobalSetting mSetting; + + public BugreportTile(Host host) { + super(host); + mSetting = new GlobalSetting(mContext, mHandler, Global.BUGREPORT_IN_POWER_MENU) { + @Override + protected void handleValueChanged(int value) { + handleRefreshState(null); + } + }; + } + + @Override + protected State newTileState() { + return new State(); + } + + @Override + public void dispose() { + mSetting.dispose(); + } + + @Override + protected void handleClick() { + mHost.collapsePanels(); + showBugreportDialog(); + } + + @Override + protected void handleUpdateState(State state, Object pushArg) { + state.visible = mSetting.getValue() != 0; + state.iconId = com.android.internal.R.drawable.stat_sys_adb; + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bugreport); + state.label = mContext.getString(com.android.internal.R.string.bugreport_title); + } + + private void showBugreportDialog() { + final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + // Add a little delay before executing, to give the + // dialog a chance to go away before it takes a + // screenshot. + mHandler.postDelayed(new Runnable() { + @Override public void run() { + try { + ActivityManagerNative.getDefault().requestBugReport(); + } catch (RemoteException e) { + } + } + }, 500); + } + } + }); + builder.setMessage(com.android.internal.R.string.bugreport_message); + builder.setTitle(com.android.internal.R.string.bugreport_title); + builder.setCancelable(true); + final Dialog dialog = builder.create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + try { + WindowManagerGlobal.getWindowManagerService().dismissKeyguard(); + } catch (RemoteException e) { + } + dialog.show(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java new file mode 100644 index 0000000..e75bb17 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.app.Dialog; +import android.content.Intent; +import android.media.MediaRouter; +import android.provider.Settings; +import android.view.View; +import android.view.WindowManager; + +import com.android.internal.app.MediaRouteDialogPresenter; +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.CastController; + +/** Quick settings tile: Cast **/ +public class CastTile extends QSTile<QSTile.BooleanState> { + private static final Intent WIFI_DISPLAY_SETTINGS = + new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS); + + private final CastController mController; + + private boolean mShown; + + public CastTile(Host host) { + super(host); + mController = host.getCastController(); + if (mController != null) { + mController.addCallback(mCallback); + } + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + @Override + public void dispose() { + if (mController == null) return; + mController.removeCallback(mCallback); + } + + @Override + protected void handleUserSwitch(int newUserId) { + super.handleUserSwitch(newUserId); + if (mController == null) return; + mController.setCurrentUserId(newUserId); + } + + @Override + protected void handleShown(boolean shown) { + if (mShown == shown) return; + if (mController == null) return; + mShown = shown; + mController.setDiscovering(mShown); + } + + @Override + protected void handleClick() { + mHost.collapsePanels(); + + final Dialog[] dialog = new Dialog[1]; + dialog[0] = MediaRouteDialogPresenter.createDialog(mContext, + MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, + new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog[0].dismiss(); + mHost.startSettingsActivity(WIFI_DISPLAY_SETTINGS); + } + }); + dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); + dialog[0].show(); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + state.visible = true; + state.label = mContext + .getString(R.string.quick_settings_remote_display_no_connection_label); + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_cast); + if (arg instanceof CallbackInfo) { + final CallbackInfo cb = (CallbackInfo) arg; + if (cb.connectedRouteName != null) { + state.value = !cb.connecting; + } + } + } + + private static class CallbackInfo { + boolean enabled; + boolean connecting; + String connectedRouteName; + } + + private final CastController.Callback mCallback = new CastController.Callback() { + @Override + public void onStateChanged(boolean enabled, boolean connecting, + String connectedRouteName) { + final CallbackInfo info = new CallbackInfo(); // TODO pool + info.enabled = enabled; + info.connecting = connecting; + info.connectedRouteName = connectedRouteName; + refreshState(info); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java new file mode 100644 index 0000000..86a4e79 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTileView; +import com.android.systemui.qs.SignalTileView; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; + +/** Quick settings tile: Cellular **/ +public class CellularTile extends QSTile<QSTile.SignalState> { + private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName( + "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity")); + + private final NetworkController mController; + + public CellularTile(Host host) { + super(host); + mController = host.getNetworkController(); + mController.addNetworkSignalChangedCallback(mCallback); + } + + @Override + protected SignalState newTileState() { + return new SignalState(); + } + + @Override + public void dispose() { + mController.removeNetworkSignalChangedCallback(mCallback); + } + + @Override + public QSTileView createTileView(Context context) { + return new SignalTileView(context); + } + + @Override + protected void handleClick() { + mHost.startSettingsActivity(CELLULAR_SETTINGS); + } + + @Override + protected void handleUpdateState(SignalState state, Object arg) { + state.visible = mController.hasMobileDataFeature(); + if (!state.visible) return; + final CallbackInfo cb = (CallbackInfo) arg; + if (cb == null) return; + + final Resources r = mContext.getResources(); + state.iconId = cb.enabled && (cb.mobileSignalIconId > 0) + ? cb.mobileSignalIconId + : R.drawable.ic_qs_signal_no_signal; + state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled + ? cb.dataTypeIconId + : 0; + state.activityIn = cb.enabled && cb.activityIn; + state.activityOut = cb.enabled && cb.activityOut; + + state.label = cb.enabled + ? removeTrailingPeriod(cb.enabledDesc) + : r.getString(R.string.quick_settings_rssi_emergency_only); + + final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0) + ? cb.signalContentDescription + : r.getString(R.string.accessibility_no_signal); + final String dataContentDesc = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled + ? cb.dataContentDescription + : r.getString(R.string.accessibility_no_data); + state.contentDescription = r.getString( + R.string.accessibility_quick_settings_mobile, + signalContentDesc, dataContentDesc, + state.label); + } + + // Remove the period from the network name + public static String removeTrailingPeriod(String string) { + if (string == null) return null; + final int length = string.length(); + if (string.endsWith(".")) { + return string.substring(0, length - 1); + } + return string; + } + + private static final class CallbackInfo { + boolean enabled; + boolean wifiEnabled; + int mobileSignalIconId; + String signalContentDescription; + int dataTypeIconId; + String dataContentDescription; + boolean activityIn; + boolean activityOut; + String enabledDesc; + } + + private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() { + private boolean mWifiEnabled; + + @Override + public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, + boolean activityIn, boolean activityOut, + String wifiSignalContentDescriptionId, String description) { + mWifiEnabled = enabled; + } + + @Override + public void onMobileDataSignalChanged(boolean enabled, + int mobileSignalIconId, + String mobileSignalContentDescriptionId, int dataTypeIconId, + boolean activityIn, boolean activityOut, + String dataTypeContentDescriptionId, String description) { + final CallbackInfo info = new CallbackInfo(); // TODO pool? + info.enabled = enabled; + info.wifiEnabled = mWifiEnabled; + info.mobileSignalIconId = mobileSignalIconId; + info.signalContentDescription = mobileSignalContentDescriptionId; + info.dataTypeIconId = dataTypeIconId; + info.dataContentDescription = dataTypeContentDescriptionId; + info.activityIn = activityIn; + info.activityOut = activityOut; + info.enabledDesc = description; + refreshState(info); + } + + @Override + public void onAirplaneModeChanged(boolean enabled) { + // noop + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java new file mode 100644 index 0000000..66740af --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.provider.Settings.Secure; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.SecureSetting; + +/** Quick settings tile: Invert colors **/ +public class ColorInversionTile extends QSTile<QSTile.BooleanState> { + + private final SecureSetting mSetting; + + private boolean mVisible; + + public ColorInversionTile(Host host) { + super(host); + + mSetting = new SecureSetting(mContext, mHandler, + Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) { + @Override + protected void handleValueChanged(int value) { + handleRefreshState(value); + } + }; + + refreshState(); + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + @Override + public void dispose() { + mSetting.dispose(); + } + + @Override + protected void handleUserSwitch(int newUserId) { + mSetting.rebindForCurrentUser(); + } + + @Override + protected void handleClick() { + mSetting.setValue(mState.value ? 0 : 1); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue(); + final boolean enabled = value != 0; + if (enabled) { + mVisible = true; + } + state.visible = mVisible; + state.value = enabled; + state.label = mContext.getString(R.string.quick_settings_inversion_label); + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_invert_colors); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java new file mode 100644 index 0000000..1a67afc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.Intent; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.TetheringController; + +/** Quick settings tile: Hotspot **/ +public class HotspotTile extends QSTile<QSTile.State> { + private static final Intent TETHER_SETTINGS = new Intent() + .setClassName("com.android.settings", "com.android.settings.TetherSettings"); + + // TODO: implement. see com.android.settings.TetherSettings + + private final TetheringController mController; + + public HotspotTile(Host host) { + super(host); + mController = host.getTetheringController(); + } + + @Override + protected State newTileState() { + return new State(); + } + + @Override + public void dispose() { + + } + + @Override + protected void handleClick() { + mHost.startSettingsActivity(TETHER_SETTINGS); + } + + @Override + protected void handleUpdateState(State state, Object arg) { + state.visible = mController != null; + state.label = mContext.getString(R.string.quick_settings_hotspot_label); + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_hotspot); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java new file mode 100644 index 0000000..d32f98f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.LocationController; +import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback; + +/** Quick settings tile: Location **/ +public class LocationTile extends QSTile<QSTile.BooleanState> { + + private final LocationController mController; + + public LocationTile(Host host) { + super(host); + mController = host.getLocationController(); + mController.addSettingsChangedCallback(mCallback); + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + public void dispose() { + mController.removeSettingsChangedCallback(mCallback); + } + + @Override + protected void handleClick() { + final boolean wasEnabled = (Boolean) mState.value; + final boolean changed = mController.setLocationEnabled(!wasEnabled); + if (!wasEnabled && changed) { + // If we've successfully switched from location off to on, close the + // notifications tray to show the network location provider consent dialog. + mHost.collapsePanels(); + } + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final boolean locationEnabled = mController.isLocationEnabled(); + state.visible = true; + state.value = locationEnabled; + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location); + if (locationEnabled) { + state.iconId = R.drawable.ic_qs_location_on; + state.label = mContext.getString(R.string.quick_settings_location_label); + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_location, + mContext.getString(R.string.accessibility_desc_on)); + } else { + state.iconId = R.drawable.ic_qs_location_off; + state.label = mContext.getString(R.string.quick_settings_location_off_label); + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_location, + mContext.getString(R.string.accessibility_desc_off)); + } + } + + private final LocationSettingsChangeCallback mCallback = new LocationSettingsChangeCallback() { + @Override + public void onLocationSettingsChanged(boolean enabled) { + refreshState(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java new file mode 100644 index 0000000..36a579c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioManager; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; + +/** Quick settings tile: Ringer mode **/ +public class RingerModeTile extends QSTile<RingerModeTile.IntState> { + + private final AudioManager mAudioManager; + + public RingerModeTile(Host host) { + super(host); + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); + mContext.registerReceiver(mReceiver, filter); + } + + @Override + protected IntState newTileState() { + return new IntState(); + } + + @Override + public void dispose() { + mContext.unregisterReceiver(mReceiver); + } + + @Override + protected void handleClick() { + final int oldValue = (Integer) mState.value; + final int newValue = + oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE + : oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT + : AudioManager.RINGER_MODE_NORMAL; + + mAudioManager.setRingerMode(newValue); + } + + @Override + protected void handleUpdateState(IntState state, Object arg) { + final int ringerMode = mAudioManager.getRingerMode(); + state.visible = true; + state.value = ringerMode; + if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_vibrate); + state.label = "Vibrate"; + } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) { + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_silent); + state.label = "Silent"; + } else { + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_audible); + state.label = "Audible"; + } + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) { + refreshState(); + } + } + }; + + public static class IntState extends QSTile.State { + public int value; + + @Override + public boolean copyTo(State other) { + final IntState o = (IntState) other; + final boolean changed = o.value != value; + o.value = value; + return super.copyTo(other) || changed; + } + + @Override + protected StringBuilder toStringBuilder() { + final StringBuilder rt = super.toStringBuilder(); + rt.insert(rt.length() - 1, ",value=" + value); + return rt; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java new file mode 100644 index 0000000..1f00824 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.res.Configuration; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; + +/** Quick settings tile: Rotation **/ +public class RotationLockTile extends QSTile<QSTile.BooleanState> { + + private final RotationLockController mController; + + public RotationLockTile(Host host) { + super(host); + mController = host.getRotationLockController(); + if (mController == null) return; + mController.addRotationLockControllerCallback(mCallback); + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + public void dispose() { + if (mController == null) return; + mController.removeRotationLockControllerCallback(mCallback); + } + + @Override + protected void handleClick() { + if (mController == null) return; + mController.setRotationLocked(mState.value); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + if (mController == null) return; + final boolean rotationLocked = mController.isRotationLocked(); + state.visible = mController.isRotationLockAffordanceVisible(); + state.value = !rotationLocked; + if (rotationLocked) { + final int lockOrientation = mController.getRotationLockOrientation(); + final int label = lockOrientation == Configuration.ORIENTATION_PORTRAIT + ? R.string.quick_settings_rotation_locked_portrait_label + : lockOrientation == Configuration.ORIENTATION_LANDSCAPE + ? R.string.quick_settings_rotation_locked_landscape_label + : R.string.quick_settings_rotation_locked_label; + state.iconId = R.drawable.ic_qs_rotation_lock; + state.label = mContext.getString(label); + } else { + state.iconId = R.drawable.ic_qs_rotation; + state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label); + } + } + + private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() { + @Override + public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { + refreshState(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java new file mode 100644 index 0000000..e08a6fa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.provider.Settings; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTileView; +import com.android.systemui.qs.SignalTileView; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; + +/** Quick settings tile: Wifi **/ +public class WifiTile extends QSTile<QSTile.SignalState> { + private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); + + private final NetworkController mController; + + public WifiTile(Host host) { + super(host); + mController = host.getNetworkController(); + mController.addNetworkSignalChangedCallback(mCallback); + } + + @Override + protected SignalState newTileState() { + return new SignalState(); + } + + @Override + public void dispose() { + mController.removeNetworkSignalChangedCallback(mCallback); + } + + @Override + public QSTileView createTileView(Context context) { + return new SignalTileView(context); + } + + @Override + protected void handleClick() { + mController.setWifiEnabled(!mState.enabled); + } + + @Override + protected void handleSecondaryClick() { + mHost.startSettingsActivity(WIFI_SETTINGS); + } + + @Override + protected void handleUpdateState(SignalState state, Object arg) { + if (arg == null) return; + state.visible = true; + CallbackInfo cb = (CallbackInfo) arg; + + boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null); + boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null); + state.enabled = wifiConnected; + state.connected = wifiConnected; + state.activityIn = cb.enabled && cb.activityIn; + state.activityOut = cb.enabled && cb.activityOut; + final String signalContentDescription; + final Resources r = mContext.getResources(); + if (wifiConnected) { + state.iconId = cb.wifiSignalIconId; + state.label = removeDoubleQuotes(cb.enabledDesc); + signalContentDescription = cb.wifiSignalContentDescription; + } else if (wifiNotConnected) { + state.iconId = R.drawable.ic_qs_wifi_0; + state.label = r.getString(R.string.quick_settings_wifi_label); + signalContentDescription = r.getString(R.string.accessibility_no_wifi); + } else { + state.iconId = R.drawable.ic_qs_wifi_no_network; + state.label = r.getString(R.string.quick_settings_wifi_off_label); + signalContentDescription = r.getString(R.string.accessibility_wifi_off); + } + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_wifi, + signalContentDescription, + state.connected ? state.label : ""); + } + + private static String removeDoubleQuotes(String string) { + if (string == null) return null; + final int length = string.length(); + if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { + return string.substring(1, length - 1); + } + return string; + } + + private static final class CallbackInfo { + boolean enabled; + int wifiSignalIconId; + String enabledDesc; + boolean activityIn; + boolean activityOut; + String wifiSignalContentDescription; + } + + private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() { + @Override + public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, + boolean activityIn, boolean activityOut, + String wifiSignalContentDescriptionId, String description) { + final CallbackInfo info = new CallbackInfo(); + info.enabled = enabled; + info.wifiSignalIconId = wifiSignalIconId; + info.enabledDesc = description; + info.activityIn = activityIn; + info.activityOut = activityOut; + info.wifiSignalContentDescription = wifiSignalContentDescriptionId; + refreshState(info); + } + + @Override + public void onMobileDataSignalChanged(boolean enabled, + int mobileSignalIconId, + String mobileSignalContentDescriptionId, int dataTypeIconId, + boolean activityIn, boolean activityOut, + String dataTypeContentDescriptionId, String description) { + // noop + } + + @Override + public void onAirplaneModeChanged(boolean enabled) { + // noop + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java new file mode 100644 index 0000000..dceb856 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings; +import android.service.notification.Condition; +import android.util.AttributeSet; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.ListView; +import android.widget.RadioButton; +import android.widget.RelativeLayout; +import android.widget.Switch; +import android.widget.TextView; + +import com.android.systemui.R; +import com.android.systemui.qs.QSImageView; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.ZenModeController; + +import java.util.HashSet; + +/** Quick settings control panel: Zen mode **/ +public class ZenModeDetail extends RelativeLayout { + private static final String TAG = "ZenModeDetail"; + private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); + private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240 }; + + private final H mHandler = new H(); + + private int mMinutesIndex = 3; + private Context mContext; + private ZenModeTile mTile; + private QSTile.Host mHost; + private ZenModeController mController; + + private Switch mSwitch; + private ConditionAdapter mAdapter; + + public ZenModeDetail(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void init(ZenModeTile tile) { + mTile = tile; + mHost = mTile.getHost(); + mContext = getContext(); + mController = mHost.getZenModeController(); + + final QSImageView close = (QSImageView) findViewById(android.R.id.button1); + close.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_close)); + close.setEnabledVersion(true); + close.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mTile.showDetail(false); + } + }); + mSwitch = (Switch) findViewById(android.R.id.checkbox); + mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mController.setZen(isChecked); + } + }); + mSwitch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final boolean isChecked = mSwitch.isChecked(); + mController.setZen(isChecked); + if (!isChecked) { + mTile.showDetail(false); + } + } + }); + + final View moreSettings = findViewById(android.R.id.button2); + moreSettings.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mHost.startSettingsActivity(ZEN_SETTINGS); + mTile.showDetail(false); + } + }); + final ListView conditions = (ListView) findViewById(android.R.id.content); + mAdapter = new ConditionAdapter(mContext); + conditions.setAdapter(mAdapter); + mAdapter.add(updateTimeCondition()); + + updateZen(mController.isZen()); + } + + private Condition updateTimeCondition() { + final int minutes = MINUTES[mMinutesIndex]; + final long millis = System.currentTimeMillis() + minutes * 60 * 1000; + final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android") + .appendPath("countdown").appendPath(Long.toString(millis)).build(); + final int num = minutes < 60 ? minutes : minutes / 60; + final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours"; + return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE, + Condition.FLAG_RELEVANT_NOW); + } + + private void editTimeCondition(int delta) { + final int i = mMinutesIndex + delta; + if (i < 0 || i >= MINUTES.length) return; + mMinutesIndex = i; + mAdapter.remove(mAdapter.getItem(0)); + final Condition c = updateTimeCondition(); + mAdapter.insert(c, 0); + select(c); + } + + private void select(Condition condition) { + mController.select(condition); + } + + private void updateZen(boolean zen) { + mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget(); + } + + private void updateConditions(Condition[] conditions) { + if (conditions == null) return; + mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget(); + } + + private void handleUpdateZen(boolean zen) { + mSwitch.setChecked(zen); + } + + private void handleUpdateConditions(Condition[] conditions) { + for (int i = mAdapter.getCount() - 1; i > 0; i--) { + mAdapter.remove(mAdapter.getItem(i)); + } + for (Condition condition : conditions) { + mAdapter.add(condition); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mController.addCallback(mCallback); + mController.requestConditions(true); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mController.removeCallback(mCallback); + mController.requestConditions(false); + } + + private final class H extends Handler { + private static final int UPDATE_ZEN = 1; + private static final int UPDATE_CONDITIONS = 2; + + public H() { + super(Looper.getMainLooper()); + } + + @Override + public void handleMessage(Message msg) { + if (msg.what == UPDATE_ZEN) { + handleUpdateZen(msg.arg1 == 1); + } else if (msg.what == UPDATE_CONDITIONS) { + handleUpdateConditions((Condition[])msg.obj); + } + } + } + + private final ZenModeController.Callback mCallback = new ZenModeController.Callback() { + @Override + public void onZenChanged(boolean zen) { + updateZen(zen); + } + public void onConditionsChanged(Condition[] conditions) { + updateConditions(conditions); + } + }; + + private final class ConditionAdapter extends ArrayAdapter<Condition> { + private final LayoutInflater mInflater; + private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>(); + + public ConditionAdapter(Context context) { + super(context, 0); + mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme)); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final Condition condition = getItem(position); + final boolean enabled = condition.state == Condition.STATE_TRUE; + + final View row = convertView != null ? convertView : mInflater + .inflate(R.layout.qs_zen_mode_detail_condition, parent, false); + final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox); + mRadioButtons.add(rb); + rb.setEnabled(enabled); + rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + for (RadioButton otherButton : mRadioButtons) { + if (otherButton == rb) continue; + otherButton.setChecked(false); + } + select(condition); + } + } + }); + final TextView title = (TextView) row.findViewById(android.R.id.title); + title.setText(condition.summary); + title.setEnabled(enabled); + title.setAlpha(enabled ? 1 : .5f); + final QSImageView button1 = (QSImageView) row.findViewById(android.R.id.button1); + button1.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_minus)); + button1.setEnabledVersion(true); + button1.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + rb.setChecked(true); + editTimeCondition(-1); + } + }); + + final QSImageView button2 = (QSImageView) row.findViewById(android.R.id.button2); + button2.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_plus)); + button2.setEnabledVersion(true); + button2.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + rb.setChecked(true); + editTimeCondition(1); + } + }); + title.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + rb.setChecked(true); + } + }); + if (position != 0) { + button1.setVisibility(View.GONE); + button2.setVisibility(View.GONE); + } + if (position == 0 && mRadioButtons.size() == 1) { + rb.setChecked(true); + } + return row; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java new file mode 100644 index 0000000..83918e8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles; + +import android.content.Context; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.ZenModeController; + +/** Quick settings tile: Zen mode **/ +public class ZenModeTile extends QSTile<QSTile.BooleanState> { + private final ZenModeController mController; + + public ZenModeTile(Host host) { + super(host); + mController = host.getZenModeController(); + mController.addCallback(mCallback); + } + + @Override + public View createDetailView(Context context, ViewGroup root) { + final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme); + final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext) + .inflate(R.layout.qs_zen_mode_detail, root, false); + v.init(this); + return v; + } + + @Override + protected BooleanState newTileState() { + return new BooleanState(); + } + + @Override + public void dispose() { + mController.removeCallback(mCallback); + } + + @Override + protected void handleClick() { + final boolean newZen = !mState.value; + mController.setZen(newZen); + if (newZen) { + showDetail(true); + } + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen(); + state.value = zen; + state.visible = true; + state.iconId = R.drawable.stat_sys_zen_limited; + state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_zen); + state.label = mContext.getString(R.string.zen_mode_title); + } + + private final ZenModeController.Callback mCallback = new ZenModeController.Callback() { + @Override + public void onZenChanged(boolean zen) { + refreshState(zen); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 89da08f..2bc6f9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -28,19 +28,19 @@ import android.widget.ImageView; import android.widget.LinearLayout; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkControllerImpl; // Intimately tied to the design of res/layout/signal_cluster_view.xml public class SignalClusterView extends LinearLayout - implements NetworkController.SignalCluster { + implements NetworkControllerImpl.SignalCluster { static final boolean DEBUG = false; static final String TAG = "SignalClusterView"; static final PorterDuffColorFilter PROBLEM_FILTER = new PorterDuffColorFilter(0xffab653b, PorterDuff.Mode.SRC_ATOP); - NetworkController mNC; + NetworkControllerImpl mNC; private boolean mWifiVisible = false; private int mWifiStrengthId = 0; @@ -67,7 +67,7 @@ public class SignalClusterView super(context, attrs, defStyle); } - public void setNetworkController(NetworkController nc) { + public void setNetworkController(NetworkControllerImpl nc) { if (DEBUG) Log.d(TAG, "NetworkController=" + nc); mNC = nc; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index a3cf0f2..869edff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -27,7 +27,7 @@ import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.DemoMode; import com.android.systemui.R; import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.policy.LocationController; +import com.android.systemui.statusbar.policy.LocationControllerImpl; public class DemoStatusIcons extends LinearLayout implements DemoMode { private final LinearLayout mStatusIcons; @@ -74,9 +74,9 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { } String location = args.getString("location"); if (location != null) { - int iconId = location.equals("show") ? LocationController.LOCATION_STATUS_ICON_ID + int iconId = location.equals("show") ? LocationControllerImpl.LOCATION_STATUS_ICON_ID : 0; - updateSlot(LocationController.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId); + updateSlot(LocationControllerImpl.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId); } String alarm = args.getString("alarm"); if (alarm != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 150db63..9054fe3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -45,7 +45,7 @@ public class NotificationPanelView extends PanelView implements PhoneStatusBar mStatusBar; private StatusBarHeaderView mHeader; - private QuickSettingsContainerView mQsContainer; + private View mQsContainer; private View mKeyguardStatusView; private ObservableScrollView mScrollView; private View mStackScrollerContainer; @@ -106,7 +106,7 @@ public class NotificationPanelView extends PanelView implements mHeader.setOverlayParent(this); mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mStackScrollerContainer = findViewById(R.id.notification_container_parent); - mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container); + mQsContainer = findViewById(R.id.quick_settings_container); mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view); mScrollView.setListener(this); mNotificationStackScroller = (NotificationStackScrollLayout) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index e7da4f9..922ac05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -92,6 +92,8 @@ import com.android.systemui.DemoMode; import com.android.systemui.EventLogTags; import com.android.systemui.R; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.qs.QSPanel; +import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper; @@ -105,13 +107,15 @@ import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.BluetoothControllerImpl; +import com.android.systemui.statusbar.policy.CastControllerImpl; import com.android.systemui.statusbar.policy.DateView; import com.android.systemui.statusbar.policy.HeadsUpNotificationView; -import com.android.systemui.statusbar.policy.LocationController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.LocationControllerImpl; +import com.android.systemui.statusbar.policy.NetworkControllerImpl; +import com.android.systemui.statusbar.policy.RotationLockControllerImpl; +import com.android.systemui.statusbar.policy.ZenModeControllerImpl; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener; import com.android.systemui.statusbar.stack.StackScrollState.ViewState; @@ -180,12 +184,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, PhoneStatusBarPolicy mIconPolicy; // These are no longer handled by the policy, because we need custom strategies for them - BluetoothController mBluetoothController; + BluetoothControllerImpl mBluetoothController; BatteryController mBatteryController; - LocationController mLocationController; - NetworkController mNetworkController; - RotationLockController mRotationLockController; + LocationControllerImpl mLocationController; + NetworkControllerImpl mNetworkController; + RotationLockControllerImpl mRotationLockController; UserInfoController mUserInfoController; + ZenModeControllerImpl mZenModeController; + CastControllerImpl mCastController; int mNaturalBarHeight = -1; int mIconSize = -1; @@ -226,9 +232,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, TextView mNotificationPanelDebugText; // settings - QuickSettings mQS; View mFlipSettingsView; - QuickSettingsContainerView mSettingsContainer; + private QSPanel mQSPanel; // top bar StatusBarHeaderView mHeader; @@ -660,15 +665,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, setAreThereNotifications(); // Other icons - mLocationController = new LocationController(mContext); // will post a notification + mLocationController = new LocationControllerImpl(mContext); // will post a notification mBatteryController = new BatteryController(mContext); - mNetworkController = new NetworkController(mContext); - mBluetoothController = new BluetoothController(mContext); - if (mContext.getResources().getBoolean(R.bool.config_showRotationLock) - || QuickSettings.DEBUG_GONE_TILES) { - mRotationLockController = new RotationLockController(mContext); + mNetworkController = new NetworkControllerImpl(mContext); + mBluetoothController = new BluetoothControllerImpl(mContext); + if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { + mRotationLockController = new RotationLockControllerImpl(mContext); } mUserInfoController = new UserInfoController(mContext); + mZenModeController = new ZenModeControllerImpl(mContext, mHandler); + mCastController = new CastControllerImpl(mContext); final SignalClusterView signalCluster = (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); @@ -717,18 +723,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // updateCarrierLabelVisibility(false); } - // Quick Settings needs a container to survive - mSettingsContainer = (QuickSettingsContainerView) - mStatusBarWindow.findViewById(R.id.quick_settings_container); - mFlipSettingsView = mSettingsContainer; - if (mSettingsContainer != null) { - mQS = new QuickSettings(mContext, mSettingsContainer); - mQS.setService(this); - mQS.setBar(mStatusBarView); - mQS.setup(mNetworkController, mBluetoothController, mBatteryController, - mLocationController, mRotationLockController); - } else { - mQS = null; // fly away, be free + // Set up the quick settings tile panel + mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); + if (mQSPanel != null) { + final QSTileHost qsh = new QSTileHost(mContext, this, + mBluetoothController, mLocationController, mRotationLockController, + mNetworkController, mZenModeController, null /*tethering*/, + mCastController); + for (QSTile<?> tile : qsh.getTiles()) { + mQSPanel.addTile(tile); + } + mHeader.setQSPanel(mQSPanel); } // User info. Trigger first load. @@ -1471,7 +1476,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } - public Handler getHandler() { + private Handler getHandler() { return mHandler; } @@ -1514,6 +1519,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } + private final Runnable mAnimateCollapsePanels = new Runnable() { + @Override + public void run() { + animateCollapsePanels(); + } + }; + + public void postAnimateCollapsePanels() { + mHandler.post(mAnimateCollapsePanels); + } + public void animateCollapsePanels(int flags) { if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { return; @@ -1591,7 +1607,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final int FLIP_DURATION_IN = 225; final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT); - Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim; + Animator mScrollViewAnim, mClearButtonAnim; @Override public void animateExpandNotificationsPanel() { @@ -1662,7 +1678,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStatusBarView.collapseAllPanels(/*animate=*/ false); // reset things to their proper state - if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel(); if (mScrollViewAnim != null) mScrollViewAnim.cancel(); if (mClearButtonAnim != null) mClearButtonAnim.cancel(); @@ -1984,7 +1999,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } setNavigationIconHints(flags); - if (mQS != null) mQS.setImeWindowStatus(vis > 0); } @Override @@ -2383,11 +2397,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, * meantime, just update the things that we know change. */ void updateResources() { - final Context context = mContext; - final Resources res = context.getResources(); - - // Update the QuickSettings container - if (mQS != null) mQS.updateResources(); + // Update the quick setting tiles + if (mQSPanel != null) mQSPanel.updateResources(); loadDimens(); } @@ -2546,10 +2557,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0; } - public void startSettingsActivity(String action) { - if (mQS != null) { - mQS.startSettingsActivity(action); + public void postStartSettingsActivity(final Intent intent) { + mHandler.post(new Runnable() { + @Override + public void run() { + handleStartSettingsActivity(intent, true /*onlyProvisioned*/); + } + }); + } + + private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) { + if (onlyProvisioned && !isDeviceProvisioned()) return; + try { + // Dismiss the lock screen when Settings starts. + ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); + } catch (RemoteException e) { } + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); + animateCollapsePanels(); + } + + public void startSettingsActivity(String action) { + postStartSettingsActivity(new Intent(action)); } private static class FastColorDrawable extends Drawable { @@ -2711,7 +2741,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardStatusView.setVisibility(View.GONE); mKeyguardIndicationTextView.setVisibility(View.GONE); } - mSettingsContainer.setKeyguardShowing(mState == StatusBarState.KEYGUARD); if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { mKeyguardBottomArea.setVisibility(View.VISIBLE); mHeader.setKeyguardShowing(true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java new file mode 100644 index 0000000..1fe3be5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.VectorDrawable; +import android.os.HandlerThread; +import android.os.Looper; + +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.tiles.AirplaneModeTile; +import com.android.systemui.qs.tiles.BluetoothTile; +import com.android.systemui.qs.tiles.BugreportTile; +import com.android.systemui.qs.tiles.CastTile; +import com.android.systemui.qs.tiles.CellularTile; +import com.android.systemui.qs.tiles.ColorInversionTile; +import com.android.systemui.qs.tiles.LocationTile; +import com.android.systemui.qs.tiles.RingerModeTile; +import com.android.systemui.qs.tiles.RotationLockTile; +import com.android.systemui.qs.tiles.HotspotTile; +import com.android.systemui.qs.tiles.WifiTile; +import com.android.systemui.qs.tiles.ZenModeTile; +import com.android.systemui.settings.CurrentUserTracker; +import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.CastController; +import com.android.systemui.statusbar.policy.LocationController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.TetheringController; +import com.android.systemui.statusbar.policy.ZenModeController; + +import java.util.ArrayList; +import java.util.List; + +/** Platform implementation of the quick settings tile host **/ +public class QSTileHost implements QSTile.Host { + + private final Context mContext; + private final PhoneStatusBar mStatusBar; + private final BluetoothController mBluetooth; + private final LocationController mLocation; + private final RotationLockController mRotation; + private final NetworkController mNetwork; + private final ZenModeController mZen; + private final TetheringController mTethering; + private final CastController mCast; + private final Looper mLooper; + private final CurrentUserTracker mUserTracker; + private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>(); + + public QSTileHost(Context context, PhoneStatusBar statusBar, + BluetoothController bluetooth, LocationController location, + RotationLockController rotation, NetworkController network, + ZenModeController zen, TetheringController tethering, + CastController cast) { + mContext = context; + mStatusBar = statusBar; + mBluetooth = bluetooth; + mLocation = location; + mRotation = rotation; + mNetwork = network; + mZen = zen; + mTethering = tethering; + mCast = cast; + + final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName()); + ht.start(); + mLooper = ht.getLooper(); + + mTiles.add(new WifiTile(this)); + mTiles.add(new BluetoothTile(this)); + mTiles.add(new ColorInversionTile(this)); + mTiles.add(new CellularTile(this)); + mTiles.add(new AirplaneModeTile(this)); + mTiles.add(new ZenModeTile(this)); + mTiles.add(new RingerModeTile(this)); + mTiles.add(new RotationLockTile(this)); + mTiles.add(new LocationTile(this)); + mTiles.add(new CastTile(this)); + mTiles.add(new HotspotTile(this)); + mTiles.add(new BugreportTile(this)); + + mUserTracker = new CurrentUserTracker(mContext) { + @Override + public void onUserSwitched(int newUserId) { + for (QSTile<?> tile : mTiles) { + tile.userSwitch(newUserId); + } + } + }; + mUserTracker.startTracking(); + } + + @Override + public List<QSTile<?>> getTiles() { + return mTiles; + } + + @Override + public void startSettingsActivity(final Intent intent) { + mStatusBar.postStartSettingsActivity(intent); + } + + @Override + public void warn(String message, Throwable t) { + // already logged + } + + @Override + public void collapsePanels() { + mStatusBar.postAnimateCollapsePanels(); + } + + @Override + public Looper getLooper() { + return mLooper; + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public VectorDrawable getVectorDrawable(int resId) { + return (VectorDrawable) mContext.getDrawable(resId); + } + + @Override + public BluetoothController getBluetoothController() { + return mBluetooth; + } + + @Override + public LocationController getLocationController() { + return mLocation; + } + + @Override + public RotationLockController getRotationLockController() { + return mRotation; + } + + @Override + public NetworkController getNetworkController() { + return mNetwork; + } + + @Override + public ZenModeController getZenModeController() { + return mZen; + } + + @Override + public TetheringController getTetheringController() { + return mTethering; + } + + @Override + public CastController getCastController() { + return mCast; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java deleted file mode 100644 index 8ce7279..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.animation.ValueAnimator; -import android.app.ActivityManagerNative; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.PendingIntent; -import android.app.admin.DevicePolicyManager; -import android.bluetooth.BluetoothAdapter; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.UserInfo; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.hardware.display.DisplayManager; -import android.media.MediaRouter; -import android.net.wifi.WifiManager; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.AlarmClock; -import android.provider.ContactsContract; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Profile; -import android.provider.Settings; -import android.security.KeyChain; -import android.text.TextUtils.TruncateAt; -import android.util.Log; -import android.util.Pair; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.WindowManagerGlobal; -import android.view.WindowManager.LayoutParams; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.internal.app.MediaRouteDialogPresenter; -import com.android.systemui.R; -import com.android.systemui.settings.UserSwitcherHostView; -import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState; -import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState; -import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState; -import com.android.systemui.statusbar.phone.QuickSettingsModel.State; -import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState; -import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.BluetoothController; -import com.android.systemui.statusbar.policy.LocationController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RotationLockController; - -import java.util.ArrayList; - -/** - * - */ -class QuickSettings { - static final boolean DEBUG_GONE_TILES = false; - private static final String TAG = "QuickSettings"; - public static final boolean SHOW_IME_TILE = false; - public static final boolean SHOW_ACCESSIBILITY_TILES = true; - - public static final boolean LONG_PRESS_TOGGLES = true; - - private Context mContext; - private PanelBar mBar; - private QuickSettingsModel mModel; - private ViewGroup mContainerView; - - private DevicePolicyManager mDevicePolicyManager; - private PhoneStatusBar mStatusBarService; - private BluetoothState mBluetoothState; - private BluetoothAdapter mBluetoothAdapter; - private WifiManager mWifiManager; - - private BluetoothController mBluetoothController; - private RotationLockController mRotationLockController; - private LocationController mLocationController; - - private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask; - private AsyncTask<Void, Void, Pair<Boolean, Boolean>> mQueryCertTask; - - boolean mTilesSetUp = false; - boolean mUseDefaultAvatar = false; - - private Handler mHandler; - - // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on - // configuration change) - private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles = - new ArrayList<QuickSettingsTileView>(); - - public QuickSettings(Context context, QuickSettingsContainerView container) { - mDevicePolicyManager - = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); - mContext = context; - mContainerView = container; - mModel = new QuickSettingsModel(context); - mBluetoothState = new QuickSettingsModel.BluetoothState(); - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - - mHandler = new Handler(); - - IntentFilter filter = new IntentFilter(); - filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(KeyChain.ACTION_STORAGE_CHANGED); - mContext.registerReceiver(mReceiver, filter); - - IntentFilter profileFilter = new IntentFilter(); - profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED); - profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); - mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter, - null, null); - } - - void setBar(PanelBar bar) { - mBar = bar; - } - - public void setService(PhoneStatusBar phoneStatusBar) { - mStatusBarService = phoneStatusBar; - } - - public PhoneStatusBar getService() { - return mStatusBarService; - } - - public void setImeWindowStatus(boolean visible) { - mModel.onImeWindowStatusChanged(visible); - } - - void setup(NetworkController networkController, BluetoothController bluetoothController, - BatteryController batteryController, LocationController locationController, - RotationLockController rotationLockController) { - mBluetoothController = bluetoothController; - mRotationLockController = rotationLockController; - mLocationController = locationController; - - setupQuickSettings(); - updateResources(); - applyLocationEnabledStatus(); - - networkController.addNetworkSignalChangedCallback(mModel); - bluetoothController.addStateChangedCallback(mModel); - batteryController.addStateChangedCallback(mModel); - locationController.addSettingsChangedCallback(mModel); - if (rotationLockController != null) { - rotationLockController.addRotationLockControllerCallback(mModel); - } - } - - private void queryForSslCaCerts() { - mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() { - @Override - protected Pair<Boolean, Boolean> doInBackground(Void... params) { - boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled(); - boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null; - - return Pair.create(hasCert, isManaged); - } - @Override - protected void onPostExecute(Pair<Boolean, Boolean> result) { - super.onPostExecute(result); - boolean hasCert = result.first; - boolean isManaged = result.second; - mModel.setSslCaCertWarningTileInfo(hasCert, isManaged); - } - }; - mQueryCertTask.execute(); - } - - private void queryForUserInformation() { - Context currentUserContext = null; - UserInfo userInfo = null; - try { - userInfo = ActivityManagerNative.getDefault().getCurrentUser(); - currentUserContext = mContext.createPackageContextAsUser("android", 0, - new UserHandle(userInfo.id)); - } catch (NameNotFoundException e) { - Log.e(TAG, "Couldn't create user context", e); - throw new RuntimeException(e); - } catch (RemoteException e) { - Log.e(TAG, "Couldn't get user info", e); - } - final int userId = userInfo.id; - final String userName = userInfo.name; - - final Context context = currentUserContext; - mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() { - @Override - protected Pair<String, Drawable> doInBackground(Void... params) { - final UserManager um = UserManager.get(mContext); - - // Fall back to the UserManager nickname if we can't read the name from the local - // profile below. - String name = userName; - Drawable avatar = null; - Bitmap rawAvatar = um.getUserIcon(userId); - if (rawAvatar != null) { - avatar = new BitmapDrawable(mContext.getResources(), rawAvatar); - } else { - avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user); - mUseDefaultAvatar = true; - } - - // If it's a single-user device, get the profile name, since the nickname is not - // usually valid - if (um.getUsers().size() <= 1) { - // Try and read the display name from the local profile - final Cursor cursor = context.getContentResolver().query( - Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME}, - null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME)); - } - } finally { - cursor.close(); - } - } - } - return new Pair<String, Drawable>(name, avatar); - } - - @Override - protected void onPostExecute(Pair<String, Drawable> result) { - super.onPostExecute(result); - mModel.setUserTileInfo(result.first, result.second); - mUserInfoTask = null; - } - }; - mUserInfoTask.execute(); - } - - private void setupQuickSettings() { - // Setup the tiles that we are going to be showing (including the temporary ones) - LayoutInflater inflater = LayoutInflater.from(mContext); - - addUserTiles(mContainerView, inflater); - addSystemTiles(mContainerView, inflater); - addTemporaryTiles(mContainerView, inflater); - addAccessibilityTiles(mContainerView); - - queryForUserInformation(); - queryForSslCaCerts(); - mTilesSetUp = true; - } - - public void startSettingsActivity(String action) { - Intent intent = new Intent(action); - startSettingsActivity(intent); - } - - private void startSettingsActivity(Intent intent) { - startSettingsActivity(intent, true); - } - - private void collapsePanels() { - getService().animateCollapsePanels(); - } - - private void startSettingsActivity(Intent intent, boolean onlyProvisioned) { - if (onlyProvisioned && !getService().isDeviceProvisioned()) return; - try { - // Dismiss the lock screen when Settings starts. - ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); - } catch (RemoteException e) { - } - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); - collapsePanels(); - } - - private void addAccessibilityTiles(ViewGroup parent) { - if (!DEBUG_GONE_TILES && !SHOW_ACCESSIBILITY_TILES) return; - - // Color inversion tile - final SystemSettingTile inversionTile = new SystemSettingTile(mContext); - inversionTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, - SystemSettingTile.TYPE_SECURE); - inversionTile.setFragment("Settings$AccessibilityInversionSettingsActivity"); - mModel.addInversionTile(inversionTile, inversionTile.getRefreshCallback()); - parent.addView(inversionTile); - - // Color space adjustment tile - final SystemSettingTile colorSpaceTile = new SystemSettingTile(mContext); - colorSpaceTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, - SystemSettingTile.TYPE_SECURE); - colorSpaceTile.setFragment("Settings$AccessibilityDaltonizerSettingsActivity"); - mModel.addColorSpaceTile(colorSpaceTile, colorSpaceTile.getRefreshCallback()); - parent.addView(colorSpaceTile); - } - - private void addUserTiles(final ViewGroup parent, final LayoutInflater inflater) { - QuickSettingsTileView userTile = (QuickSettingsTileView) - inflater.inflate(R.layout.quick_settings_tile, parent, false); - userTile.setContent(R.layout.quick_settings_tile_user, inflater); - userTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final UserManager um = UserManager.get(mContext); - if (um.isUserSwitcherEnabled()) { - final ViewGroup switcherParent = getService().getQuickSettingsOverlayParent(); - final UserSwitcherHostView switcher = (UserSwitcherHostView) inflater.inflate( - R.layout.user_switcher_host, switcherParent, false); - switcher.setFinishRunnable(new Runnable() { - @Override - public void run() { - switcherParent.removeView(switcher); - } - }); - switcher.refreshUsers(); - switcherParent.addView(switcher); - } else { - collapsePanels(); - Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent( - mContext, v, ContactsContract.Profile.CONTENT_URI, - ContactsContract.QuickContact.MODE_LARGE, null); - mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); - } - } - }); - mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView view, State state) { - UserState us = (UserState) state; - ImageView iv = (ImageView) view.findViewById(R.id.user_imageview); - TextView tv = (TextView) view.findViewById(R.id.user_textview); - tv.setText(state.label); - iv.setImageDrawable(us.avatar); - view.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_user, state.label)); - } - }); - parent.addView(userTile); - mDynamicSpannedTiles.add(userTile); - - // Brightness - final QuickSettingsBasicTile brightnessTile - = new QuickSettingsBasicTile(mContext); - brightnessTile.setImageResource(R.drawable.ic_qs_brightness_auto_off); - brightnessTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - collapsePanels(); - showBrightnessDialog(); - } - }); - mModel.addBrightnessTile(brightnessTile, - new QuickSettingsModel.BasicRefreshCallback(brightnessTile)); - parent.addView(brightnessTile); - mDynamicSpannedTiles.add(brightnessTile); - - // Settings tile - final QuickSettingsBasicTile settingsTile = new QuickSettingsBasicTile(mContext); - settingsTile.setImageResource(R.drawable.ic_qs_settings); - settingsTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSettingsActivity(android.provider.Settings.ACTION_SETTINGS); - } - }); - mModel.addSettingsTile(settingsTile, - new QuickSettingsModel.BasicRefreshCallback(settingsTile)); - parent.addView(settingsTile); - mDynamicSpannedTiles.add(settingsTile); - } - - private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) { - // Wi-fi - final QuickSettingsTileView wifiTile = (QuickSettingsTileView) - inflater.inflate(R.layout.quick_settings_tile, parent, false); - wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater); - wifiTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS); - } - }); - if (LONG_PRESS_TOGGLES) { - wifiTile.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - final boolean enable = - (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED); - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... args) { - // Disable tethering if enabling Wifi - final int wifiApState = mWifiManager.getWifiApState(); - if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || - (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { - mWifiManager.setWifiApEnabled(null, false); - } - - mWifiManager.setWifiEnabled(enable); - return null; - } - }.execute(); - wifiTile.setPressed(false); - return true; - }} ); - } - mModel.addWifiTile(wifiTile, new NetworkActivityCallback() { - @Override - public void refreshView(QuickSettingsTileView view, State state) { - WifiState wifiState = (WifiState) state; - ImageView iv = (ImageView) view.findViewById(R.id.image); - iv.setImageResource(wifiState.iconId); - setActivity(view, wifiState); - TextView tv = (TextView) view.findViewById(R.id.text); - tv.setText(wifiState.label); - wifiTile.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_wifi, - wifiState.signalContentDescription, - (wifiState.connected) ? wifiState.label : "")); - } - }); - parent.addView(wifiTile); - - if (mModel.deviceHasMobileData()) { - // RSSI - QuickSettingsTileView rssiTile = (QuickSettingsTileView) - inflater.inflate(R.layout.quick_settings_tile, parent, false); - rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater); - rssiTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(); - intent.setComponent(new ComponentName( - "com.android.settings", - "com.android.settings.Settings$DataUsageSummaryActivity")); - startSettingsActivity(intent); - } - }); - mModel.addRSSITile(rssiTile, new NetworkActivityCallback() { - @Override - public void refreshView(QuickSettingsTileView view, State state) { - RSSIState rssiState = (RSSIState) state; - ImageView iv = (ImageView) view.findViewById(R.id.rssi_image); - ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image); - TextView tv = (TextView) view.findViewById(R.id.rssi_textview); - // Force refresh - iv.setImageDrawable(null); - iv.setImageResource(rssiState.signalIconId); - - if (rssiState.dataTypeIconId > 0) { - iov.setImageResource(rssiState.dataTypeIconId); - } else { - iov.setImageDrawable(null); - } - setActivity(view, rssiState); - - tv.setText(state.label); - view.setContentDescription(mContext.getResources().getString( - R.string.accessibility_quick_settings_mobile, - rssiState.signalContentDescription, rssiState.dataContentDescription, - state.label)); - } - }); - parent.addView(rssiTile); - } - - // Rotation Lock - if (mRotationLockController != null) { - final QuickSettingsBasicTile rotationLockTile - = new QuickSettingsBasicTile(mContext); - rotationLockTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - final boolean locked = mRotationLockController.isRotationLocked(); - mRotationLockController.setRotationLocked(!locked); - } - }); - mModel.addRotationLockTile(rotationLockTile, mRotationLockController, - new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView view, State state) { - QuickSettingsModel.RotationLockState rotationLockState = - (QuickSettingsModel.RotationLockState) state; - view.setVisibility(rotationLockState.visible - ? View.VISIBLE : View.GONE); - if (state.iconId != 0) { - // needed to flush any cached IDs - rotationLockTile.setImageDrawable(null); - rotationLockTile.setImageResource(state.iconId); - } - if (state.label != null) { - rotationLockTile.setText(state.label); - } - } - }); - parent.addView(rotationLockTile); - } - - // Battery - final QuickSettingsTileView batteryTile = (QuickSettingsTileView) - inflater.inflate(R.layout.quick_settings_tile, parent, false); - batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater); - batteryTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY); - } - }); - mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView unused, State state) { - QuickSettingsModel.BatteryState batteryState = - (QuickSettingsModel.BatteryState) state; - String t; - if (batteryState.batteryLevel == 100) { - t = mContext.getString(R.string.quick_settings_battery_charged_label); - } else { - t = batteryState.pluggedIn - ? mContext.getString(R.string.quick_settings_battery_charging_label, - batteryState.batteryLevel) - : mContext.getString(R.string.status_bar_settings_battery_meter_format, - batteryState.batteryLevel); - } - ((TextView)batteryTile.findViewById(R.id.text)).setText(t); - batteryTile.setContentDescription( - mContext.getString(R.string.accessibility_quick_settings_battery, t)); - } - }); - parent.addView(batteryTile); - - // Bluetooth - if (mModel.deviceSupportsBluetooth() - || DEBUG_GONE_TILES) { - final QuickSettingsBasicTile bluetoothTile - = new QuickSettingsBasicTile(mContext); - bluetoothTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS); - } - }); - if (LONG_PRESS_TOGGLES) { - bluetoothTile.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - if (mBluetoothAdapter.isEnabled()) { - mBluetoothAdapter.disable(); - } else { - mBluetoothAdapter.enable(); - } - bluetoothTile.setPressed(false); - return true; - }}); - } - mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView unused, State state) { - BluetoothState bluetoothState = (BluetoothState) state; - bluetoothTile.setImageResource(state.iconId); - - /* - Resources r = mContext.getResources(); - //TODO: Show connected bluetooth device label - Set<BluetoothDevice> btDevices = - mBluetoothController.getBondedBluetoothDevices(); - if (btDevices.size() == 1) { - // Show the name of the bluetooth device you are connected to - label = btDevices.iterator().next().getName(); - } else if (btDevices.size() > 1) { - // Show a generic label about the number of bluetooth devices - label = r.getString(R.string.quick_settings_bluetooth_multiple_devices_label, - btDevices.size()); - } - */ - bluetoothTile.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_bluetooth, - bluetoothState.stateContentDescription)); - bluetoothTile.setText(state.label); - } - }); - parent.addView(bluetoothTile); - } - - // Location - final QuickSettingsBasicTile locationTile - = new QuickSettingsBasicTile(mContext); - locationTile.setImageResource(R.drawable.ic_qs_location_on); - locationTile.setTextResource(R.string.quick_settings_location_label); - locationTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); - } - }); - if (LONG_PRESS_TOGGLES) { - locationTile.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - boolean newLocationEnabledState = !mLocationController.isLocationEnabled(); - if (mLocationController.setLocationEnabled(newLocationEnabledState) - && newLocationEnabledState) { - // If we've successfully switched from location off to on, close the - // notifications tray to show the network location provider consent dialog. - Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - mContext.sendBroadcast(closeDialog); - } - return true; // Consume click - }} ); - } - mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView unused, State state) { - locationTile.setImageResource(state.iconId); - String locationState = mContext.getString( - (state.enabled) ? R.string.accessibility_desc_on - : R.string.accessibility_desc_off); - locationTile.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_location, - locationState)); - locationTile.setText(state.label); - } - }); - parent.addView(locationTile); - - // Airplane Mode - final QuickSettingsBasicTile airplaneTile - = new QuickSettingsBasicTile(mContext); - mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView unused, State state) { - airplaneTile.setImageResource(state.iconId); - - String airplaneState = mContext.getString( - (state.enabled) ? R.string.accessibility_desc_on - : R.string.accessibility_desc_off); - airplaneTile.setContentDescription( - mContext.getString(R.string.accessibility_quick_settings_airplane, - airplaneState)); - airplaneTile.setText(state.label); - } - }); - parent.addView(airplaneTile); - - // Zen Mode - final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext); - zenModeTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showZenModeDialog(); - } - }); - mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView unused, State state) { - zenModeTile.setImageResource(state.iconId); - // TODO cut new assets - zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f); - zenModeTile.getImageView().setScaleX(1.5f); - zenModeTile.getImageView().setScaleY(1.5f); - // for landscape version - zenModeTile.getTextView().setMaxLines(2); - zenModeTile.getTextView().setEllipsize(TruncateAt.END); - // TODO content description - zenModeTile.setText(state.label); - } - }); - parent.addView(zenModeTile); - } - - private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) { - // Alarm tile - final QuickSettingsBasicTile alarmTile - = new QuickSettingsBasicTile(mContext); - alarmTile.setImageResource(R.drawable.ic_qs_alarm_on); - alarmTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS); - } - }); - mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView unused, State alarmState) { - alarmTile.setText(alarmState.label); - alarmTile.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE); - alarmTile.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_alarm, alarmState.label)); - } - }); - parent.addView(alarmTile); - - // Remote Display - QuickSettingsBasicTile remoteDisplayTile - = new QuickSettingsBasicTile(mContext); - remoteDisplayTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - collapsePanels(); - - final Dialog[] dialog = new Dialog[1]; - dialog[0] = MediaRouteDialogPresenter.createDialog(mContext, - MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, - new View.OnClickListener() { - @Override - public void onClick(View v) { - dialog[0].dismiss(); - startSettingsActivity( - android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS); - } - }); - dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); - dialog[0].show(); - } - }); - mModel.addRemoteDisplayTile(remoteDisplayTile, - new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile) - .setShowWhenEnabled(true)); - parent.addView(remoteDisplayTile); - - if (SHOW_IME_TILE || DEBUG_GONE_TILES) { - // IME - final QuickSettingsBasicTile imeTile - = new QuickSettingsBasicTile(mContext); - imeTile.setImageResource(R.drawable.ic_qs_ime); - imeTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - try { - collapsePanels(); - Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); - pendingIntent.send(); - } catch (Exception e) {} - } - }); - mModel.addImeTile(imeTile, - new QuickSettingsModel.BasicRefreshCallback(imeTile) - .setShowWhenEnabled(true)); - parent.addView(imeTile); - } - - // Bug reports - final QuickSettingsBasicTile bugreportTile - = new QuickSettingsBasicTile(mContext); - bugreportTile.setImageResource(com.android.internal.R.drawable.stat_sys_adb); - bugreportTile.setTextResource(com.android.internal.R.string.bugreport_title); - bugreportTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - collapsePanels(); - showBugreportDialog(); - } - }); - mModel.addBugreportTile(bugreportTile, new QuickSettingsModel.RefreshCallback() { - @Override - public void refreshView(QuickSettingsTileView view, State state) { - view.setVisibility(state.enabled ? View.VISIBLE : View.GONE); - } - }); - parent.addView(bugreportTile); - /* - QuickSettingsTileView mediaTile = (QuickSettingsTileView) - inflater.inflate(R.layout.quick_settings_tile, parent, false); - mediaTile.setContent(R.layout.quick_settings_tile_media, inflater); - parent.addView(mediaTile); - QuickSettingsTileView imeTile = (QuickSettingsTileView) - inflater.inflate(R.layout.quick_settings_tile, parent, false); - imeTile.setContent(R.layout.quick_settings_tile_ime, inflater); - imeTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - parent.removeViewAt(0); - } - }); - parent.addView(imeTile); - */ - - // SSL CA Cert Warning. - final QuickSettingsBasicTile sslCaCertWarningTile = - new QuickSettingsBasicTile(mContext, null, R.layout.quick_settings_tile_monitoring); - sslCaCertWarningTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - collapsePanels(); - startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO); - } - }); - - sslCaCertWarningTile.setImageResource( - com.android.internal.R.drawable.indicator_input_error); - sslCaCertWarningTile.setTextResource(R.string.ssl_ca_cert_warning); - - mModel.addSslCaCertWarningTile(sslCaCertWarningTile, - new QuickSettingsModel.BasicRefreshCallback(sslCaCertWarningTile) - .setShowWhenEnabled(true)); - parent.addView(sslCaCertWarningTile); - } - - void updateResources() { - Resources r = mContext.getResources(); - - // Update the model - mModel.updateResources(); - - // Update the User, Time, and Settings tiles spans, and reset everything else - int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span); - for (QuickSettingsTileView v : mDynamicSpannedTiles) { - v.setColumnSpan(span); - } - ((QuickSettingsContainerView)mContainerView).updateResources(); - mContainerView.requestLayout(); - } - - - private void showBrightnessDialog() { - Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG); - mContext.sendBroadcast(intent); - } - - private void showBugreportDialog() { - final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - // Add a little delay before executing, to give the - // dialog a chance to go away before it takes a - // screenshot. - mHandler.postDelayed(new Runnable() { - @Override public void run() { - try { - ActivityManagerNative.getDefault() - .requestBugReport(); - } catch (RemoteException e) { - } - } - }, 500); - } - } - }); - builder.setMessage(com.android.internal.R.string.bugreport_message); - builder.setTitle(com.android.internal.R.string.bugreport_title); - builder.setCancelable(true); - final Dialog dialog = builder.create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - try { - WindowManagerGlobal.getWindowManagerService().dismissKeyguard(); - } catch (RemoteException e) { - } - dialog.show(); - } - - private void showZenModeDialog() { - final Dialog d = new Dialog(mContext); - d.requestWindowFeature(Window.FEATURE_NO_TITLE); - d.setCancelable(true); - d.setCanceledOnTouchOutside(true); - final ZenModeView v = new ZenModeView(mContext) { - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - WindowManager.LayoutParams lp = d.getWindow().getAttributes(); - lp.width = mContext.getResources() - .getDimensionPixelSize(R.dimen.zen_mode_dialog_width); - d.getWindow().setAttributes(lp); - } - }; - v.setAutoActivate(true); - v.setAdapter(new ZenModeViewAdapter(mContext) { - @Override - public void configure() { - if (mStatusBarService != null) { - mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS); - } - d.dismiss(); - } - @Override - public void close() { - d.dismiss(); - } - }); - d.setContentView(v); - d.create(); - d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); - WindowManager.LayoutParams lp = d.getWindow().getAttributes(); - lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width); - d.getWindow().setAttributes(lp); - d.show(); - } - - private void applyBluetoothStatus() { - mModel.onBluetoothStateChange(mBluetoothState); - } - - private void applyLocationEnabledStatus() { - mModel.onLocationSettingsChanged(mLocationController.isLocationEnabled()); - } - - void reloadUserInfo() { - if (mUserInfoTask != null) { - mUserInfoTask.cancel(false); - mUserInfoTask = null; - } - if (mTilesSetUp) { - queryForUserInformation(); - queryForSslCaCerts(); - } - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { - int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, - BluetoothAdapter.ERROR); - mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON); - applyBluetoothStatus(); - } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { - int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, - BluetoothAdapter.STATE_DISCONNECTED); - mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED); - applyBluetoothStatus(); - } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { - reloadUserInfo(); - } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - if (mUseDefaultAvatar) { - queryForUserInformation(); - } - } else if (KeyChain.ACTION_STORAGE_CHANGED.equals(action)) { - queryForSslCaCerts(); - } - } - }; - - private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || - Intent.ACTION_USER_INFO_CHANGED.equals(action)) { - try { - final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id; - final int changedUser = - intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); - if (changedUser == currentUser) { - reloadUserInfo(); - } - } catch (RemoteException e) { - Log.e(TAG, "Couldn't get current user id for profile change", e); - } - } - - } - }; - - private abstract static class NetworkActivityCallback - implements QuickSettingsModel.RefreshCallback { - private final long mDefaultDuration = new ValueAnimator().getDuration(); - private final long mShortDuration = mDefaultDuration / 3; - - public void setActivity(View view, ActivityState state) { - setVisibility(view.findViewById(R.id.activity_in), state.activityIn); - setVisibility(view.findViewById(R.id.activity_out), state.activityOut); - } - - private void setVisibility(View view, boolean visible) { - final float newAlpha = visible ? 1 : 0; - if (view.getAlpha() != newAlpha) { - view.animate() - .setDuration(visible ? mShortDuration : mDefaultDuration) - .alpha(newAlpha) - .start(); - } - } - } - - /** - * Quick Setting tile that represents a secure setting. This type of tile - * can toggle a URI within Settings.Secure on click and launch a Settings - * fragment on long-click. - */ - public class SystemSettingTile extends QuickSettingsBasicTile { - private static final int TYPE_GLOBAL = 0; - private static final int TYPE_SECURE = 1; - private static final int TYPE_SYSTEM = 2; - - private final QuickSettingsModel.BasicRefreshCallback mRefreshCallback; - - private String mFragment; - private String mName; - private int mType; - - public SystemSettingTile(Context context) { - super(context); - - mRefreshCallback = new QuickSettingsModel.BasicRefreshCallback(this); - mRefreshCallback.setShowWhenEnabled(true); - } - - @Override - public boolean performLongClick() { - if (mFragment != null) { - collapsePanels(); - - final Intent intent = new Intent(); - intent.setComponent(new ComponentName( - "com.android.settings", "com.android.settings." + mFragment)); - startSettingsActivity(intent); - return true; - } - return false; - } - - @Override - public boolean performClick() { - if (mName != null) { - collapsePanels(); - - final ContentResolver cr = mContext.getContentResolver(); - switch (mType) { - case TYPE_GLOBAL: { - final boolean enable = Settings.Global.getInt(cr, mName, 0) == 0; - Settings.Global.putInt(cr, mName, enable ? 1 : 0); - } break; - case TYPE_SECURE: { - final boolean enable = Settings.Secure.getIntForUser( - cr, mName, 0, UserHandle.USER_CURRENT) == 0; - Settings.Secure.putIntForUser( - cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT); - } break; - case TYPE_SYSTEM: { - final boolean enable = Settings.System.getIntForUser( - cr, mName, 0, UserHandle.USER_CURRENT) == 0; - Settings.System.putIntForUser( - cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT); - } break; - } - return true; - } - return false; - } - - /** - * Specifies the fragment within the com.android.settings package to - * launch when this tile is long-clicked. - * - * @param fragment a fragment name within the com.android.settings - * package - */ - public void setFragment(String fragment) { - mFragment = fragment; - setLongClickable(fragment != null); - } - - /** - * Specifies the setting name and type to toggle when this tile is - * clicked. - * - * @param name a setting name - * @param type the type of setting, one of: - * <ul> - * <li>{@link #TYPE_GLOBAL} - * <li>{@link #TYPE_SECURE} - * <li>{@link #TYPE_SYSTEM} - * </ul> - */ - public void setUri(String name, int type) { - mName = name; - mType = type; - setClickable(mName != null); - } - - /** - * @return the refresh callback for this tile - */ - public QuickSettingsModel.BasicRefreshCallback getRefreshCallback() { - return mRefreshCallback; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java deleted file mode 100644 index 099780c..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.systemui.R; - -class QuickSettingsBasicTile extends QuickSettingsTileView { - private final TextView mTextView; - private final ImageView mImageView; - - public QuickSettingsBasicTile(Context context) { - this(context, null); - } - - public QuickSettingsBasicTile(Context context, AttributeSet attrs) { - this(context, attrs, R.layout.quick_settings_tile_basic); - } - - public QuickSettingsBasicTile(Context context, AttributeSet attrs, int layoutId) { - super(context, attrs); - - setLayoutParams(new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - context.getResources().getDimensionPixelSize(R.dimen.quick_settings_cell_height) - )); - setBackgroundResource(R.drawable.qs_tile_background); - addView(LayoutInflater.from(context).inflate(layoutId, null), - new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT)); - mTextView = (TextView) findViewById(R.id.text); - mImageView = (ImageView) findViewById(R.id.image); - } - - @Override - void setContent(int layoutId, LayoutInflater inflater) { - throw new RuntimeException("why?"); - } - - public ImageView getImageView() { - return mImageView; - } - - public TextView getTextView() { - return mTextView; - } - - public void setImageDrawable(Drawable drawable) { - mImageView.setImageDrawable(drawable); - } - - public void setImageResource(int resId) { - mImageView.setImageResource(resId); - } - - public void setText(CharSequence text) { - mTextView.setText(text); - } - - public void setTextResource(int resId) { - mTextView.setText(resId); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java deleted file mode 100644 index c44cb0c..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.animation.LayoutTransition; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.Typeface; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import com.android.systemui.R; - -/** - * - */ -class QuickSettingsContainerView extends FrameLayout { - - private static boolean sShowScrim = true; - - private final Context mContext; - - // The number of columns in the QuickSettings grid - private int mNumColumns; - - private boolean mKeyguardShowing; - private int mMaxRows; - private int mMaxRowsOnKeyguard; - - // The gap between tiles in the QuickSettings grid - private float mCellGap; - - private ScrimView mScrim; - - public QuickSettingsContainerView(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - updateResources(); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - if (sShowScrim) { - mScrim = new ScrimView(mContext); - addView(mScrim); - } - // TODO: Setup the layout transitions - LayoutTransition transitions = getLayoutTransition(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mScrim != null) { - sShowScrim = false; - removeView(mScrim); - } - return super.onTouchEvent(event); - } - - void updateResources() { - Resources r = getContext().getResources(); - mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap); - mNumColumns = r.getInteger(R.integer.quick_settings_num_columns); - mMaxRows = r.getInteger(R.integer.quick_settings_max_rows); - mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard); - requestLayout(); - } - - void setKeyguardShowing(boolean showing) { - mKeyguardShowing = showing; - requestLayout(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Calculate the cell width dynamically - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); - int availableWidth = (int) (width - getPaddingLeft() - getPaddingRight() - - (mNumColumns - 1) * mCellGap); - float cellWidth = (float) Math.ceil(((float) availableWidth) / mNumColumns); - - // Update each of the children's widths accordingly to the cell width - final int N = getChildCount(); - int cellHeight = 0; - int cursor = 0; - int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows; - - for (int i = 0; i < N; ++i) { - if (getChildAt(i).equals(mScrim)) { - continue; - } - // Update the child's width - QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i); - if (v.getVisibility() != View.GONE) { - int row = (int) (cursor / mNumColumns); - if (row >= maxRows) continue; - - ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); - int colSpan = v.getColumnSpan(); - lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap); - - // Measure the child - int newWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); - int newHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); - v.measure(newWidthSpec, newHeightSpec); - - // Save the cell height - if (cellHeight <= 0) { - cellHeight = v.getMeasuredHeight(); - } - cursor += colSpan; - } - } - - // Set the measured dimensions. We always fill the tray width, but wrap to the height of - // all the tiles. - int numRows = (int) Math.ceil((float) cursor / mNumColumns); - int newHeight = (int) ((numRows * cellHeight) + ((numRows - 1) * mCellGap)) + - getPaddingTop() + getPaddingBottom(); - setMeasuredDimension(width, newHeight); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if (mScrim != null) { - mScrim.bringToFront(); - } - final int N = getChildCount(); - final boolean isLayoutRtl = isLayoutRtl(); - final int width = getWidth(); - - int x = getPaddingStart(); - int y = getPaddingTop(); - int cursor = 0; - int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows; - - for (int i = 0; i < N; ++i) { - if (getChildAt(i).equals(mScrim)) { - int w = right - left - getPaddingLeft() - getPaddingRight(); - int h = bottom - top - getPaddingTop() - getPaddingBottom(); - mScrim.measure( - MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); - mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom); - continue; - } - QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i); - ViewGroup.LayoutParams lp = child.getLayoutParams(); - if (child.getVisibility() != GONE) { - final int col = cursor % mNumColumns; - final int colSpan = child.getColumnSpan(); - - final int childWidth = lp.width; - final int childHeight = lp.height; - - int row = (int) (cursor / mNumColumns); - if (row >= maxRows) continue; - - // Push the item to the next row if it can't fit on this one - if ((col + colSpan) > mNumColumns) { - x = getPaddingStart(); - y += childHeight + mCellGap; - row++; - } - - final int childLeft = (isLayoutRtl) ? width - x - childWidth : x; - final int childRight = childLeft + childWidth; - - final int childTop = y; - final int childBottom = childTop + childHeight; - - // Layout the container - child.layout(childLeft, childTop, childRight, childBottom); - - // Offset the position by the cell gap or reset the position and cursor when we - // reach the end of the row - cursor += child.getColumnSpan(); - if (cursor < (((row + 1) * mNumColumns))) { - x += childWidth + mCellGap; - } else { - x = getPaddingStart(); - y += childHeight + mCellGap; - } - } - } - } - - private static final class ScrimView extends View { - private static final int SCRIM = 0x4f000000; - private static final int COLOR = 0xaf4285f4; - - private final Paint mLinePaint; - private final int mStrokeWidth; - private final Rect mTmp = new Rect(); - private final Paint mTextPaint; - private final int mTextSize; - - public ScrimView(Context context) { - super(context); - setFocusable(false); - final Resources res = context.getResources(); - mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width); - mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size); - - mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mLinePaint.setColor(COLOR); - mLinePaint.setStrokeWidth(mStrokeWidth); - mLinePaint.setStrokeJoin(Paint.Join.ROUND); - mLinePaint.setStrokeCap(Paint.Cap.ROUND); - mLinePaint.setStyle(Paint.Style.STROKE); - - mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mTextPaint.setColor(COLOR); - mTextPaint.setTextSize(mTextSize); - mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD)); - } - - @Override - protected void onDraw(Canvas canvas) { - final int w = getMeasuredWidth(); - final int h = getMeasuredHeight(); - final int f = mStrokeWidth * 3 / 4; - - canvas.drawColor(SCRIM); - canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint); - canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint); - - final int s = mStrokeWidth; - mTextPaint.setTextAlign(Paint.Align.RIGHT); - canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint); - mTextPaint.setTextAlign(Paint.Align.LEFT); - canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint); - mTextPaint.setTextAlign(Paint.Align.RIGHT); - drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s); - mTextPaint.setTextAlign(Paint.Align.LEFT); - drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s); - } - - private void drawUnder(Canvas c, String text, float x, float y) { - if (mTmp.isEmpty()) { - mTextPaint.getTextBounds(text, 0, text.length(), mTmp); - } - c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint); - } - - private Path line(float x1, float y1, float x2, float y2) { - final int a = mStrokeWidth * 2; - final Path p = new Path(); - p.moveTo(x1, y1); - p.lineTo(x2, y2); - if (y1 == y2) { - p.moveTo(x1 + a, y1 + a); - p.lineTo(x1, y1); - p.lineTo(x1 + a, y1 - a); - - p.moveTo(x2 - a, y2 - a); - p.lineTo(x2, y2); - p.lineTo(x2 - a, y2 + a); - } - if (x1 == x2) { - p.moveTo(x1 - a, y1 + a); - p.lineTo(x1, y1); - p.lineTo(x1 + a, y1 + a); - - p.moveTo(x2 - a, y2 - a); - p.lineTo(x2, y2); - p.lineTo(x2 + a, y2 - a); - } - return p; - } - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java deleted file mode 100644 index 9b90d3d..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.graphics.drawable.Drawable; -import android.media.MediaRouter; -import android.media.MediaRouter.RouteInfo; -import android.net.ConnectivityManager; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.systemui.R; -import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback; -import com.android.systemui.settings.CurrentUserTracker; -import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; -import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback; -import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; -import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; - -import java.util.List; - -class QuickSettingsModel implements BluetoothStateChangeCallback, - NetworkSignalChangedCallback, - BatteryStateChangeCallback, - BrightnessStateChangeCallback, - RotationLockControllerCallback, - LocationSettingsChangeCallback { - // Sett InputMethoManagerService - private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher"; - - /** Represents the state of a given attribute. */ - static class State { - int iconId; - String label; - boolean enabled = false; - } - static class BatteryState extends State { - int batteryLevel; - boolean pluggedIn; - } - static class ActivityState extends State { - boolean activityIn; - boolean activityOut; - } - static class RSSIState extends ActivityState { - int signalIconId; - String signalContentDescription; - int dataTypeIconId; - String dataContentDescription; - } - static class WifiState extends ActivityState { - String signalContentDescription; - boolean connected; - } - static class UserState extends State { - Drawable avatar; - } - static class BrightnessState extends State { - boolean autoBrightness; - } - static class InversionState extends State { - boolean toggled; - } - static class ColorSpaceState extends State { - boolean toggled; - int type; - } - public static class BluetoothState extends State { - boolean connected = false; - String stateContentDescription; - } - public static class RotationLockState extends State { - boolean visible = false; - } - public static class ZenModeState extends State { - int zenMode = Settings.Global.ZEN_MODE_OFF; - } - - /** The callback to update a given tile. */ - interface RefreshCallback { - public void refreshView(QuickSettingsTileView view, State state); - } - - public static class BasicRefreshCallback implements RefreshCallback { - private final QuickSettingsBasicTile mView; - private boolean mShowWhenEnabled; - - public BasicRefreshCallback(QuickSettingsBasicTile v) { - mView = v; - } - public void refreshView(QuickSettingsTileView ignored, State state) { - if (mShowWhenEnabled) { - mView.setVisibility(state.enabled ? View.VISIBLE : View.GONE); - } - if (state.iconId != 0) { - mView.setImageDrawable(null); // needed to flush any cached IDs - mView.setImageResource(state.iconId); - } - if (state.label != null) { - mView.setText(state.label); - } - } - public BasicRefreshCallback setShowWhenEnabled(boolean swe) { - mShowWhenEnabled = swe; - return this; - } - } - - /** Broadcast receive to determine if there is an alarm set. */ - private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_ALARM_CHANGED)) { - onAlarmChanged(intent); - onNextAlarmChanged(); - } - } - }; - - /** ContentObserver to determine the next alarm */ - private class NextAlarmObserver extends ContentObserver { - public NextAlarmObserver(Handler handler) { - super(handler); - } - - @Override public void onChange(boolean selfChange) { - onNextAlarmChanged(); - } - - public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver( - Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this, - UserHandle.USER_ALL); - } - } - - /** ContentObserver to watch adb */ - private class BugreportObserver extends ContentObserver { - public BugreportObserver(Handler handler) { - super(handler); - } - - @Override public void onChange(boolean selfChange) { - onBugreportChanged(); - } - - public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.BUGREPORT_IN_POWER_MENU), false, this); - } - } - - /** ContentObserver to watch brightness **/ - private class BrightnessObserver extends ContentObserver { - public BrightnessObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - onBrightnessLevelChanged(); - } - - public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.unregisterContentObserver(this); - cr.registerContentObserver( - Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), - false, this, mUserTracker.getCurrentUserId()); - cr.registerContentObserver( - Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), - false, this, mUserTracker.getCurrentUserId()); - } - } - - /** ContentObserver to watch display inversion */ - private class DisplayInversionObserver extends ContentObserver { - public DisplayInversionObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - onInversionChanged(); - } - - public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.unregisterContentObserver(this); - cr.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED), - false, this, mUserTracker.getCurrentUserId()); - cr.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED), - false, this, mUserTracker.getCurrentUserId()); - } - } - - /** ContentObserver to watch display color space adjustment */ - private class DisplayColorSpaceObserver extends ContentObserver { - public DisplayColorSpaceObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - onColorSpaceChanged(); - } - - public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.unregisterContentObserver(this); - cr.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED), - false, this, mUserTracker.getCurrentUserId()); - cr.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED), - false, this, mUserTracker.getCurrentUserId()); - cr.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER), - false, this, mUserTracker.getCurrentUserId()); - } - } - - /** ContentObserver to watch display color space adjustment */ - private class ZenModeObserver extends ContentObserver { - public ZenModeObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - onZenModeChanged(); - } - - public void startObserving() { - final ContentResolver cr = mContext.getContentResolver(); - cr.unregisterContentObserver(this); - cr.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this); - } - } - - /** Callback for changes to remote display routes. */ - private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback { - @Override - public void onRouteAdded(MediaRouter router, RouteInfo route) { - updateRemoteDisplays(); - } - @Override - public void onRouteChanged(MediaRouter router, RouteInfo route) { - updateRemoteDisplays(); - } - @Override - public void onRouteRemoved(MediaRouter router, RouteInfo route) { - updateRemoteDisplays(); - } - @Override - public void onRouteSelected(MediaRouter router, int type, RouteInfo route) { - updateRemoteDisplays(); - } - @Override - public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) { - updateRemoteDisplays(); - } - } - - private final Context mContext; - private final Handler mHandler; - private final CurrentUserTracker mUserTracker; - private final NextAlarmObserver mNextAlarmObserver; - private final BugreportObserver mBugreportObserver; - private final BrightnessObserver mBrightnessObserver; - private final DisplayInversionObserver mInversionObserver; - private final DisplayColorSpaceObserver mColorSpaceObserver; - private final ZenModeObserver mZenModeObserver; - - private final MediaRouter mMediaRouter; - private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback; - - private final boolean mHasMobileData; - - private QuickSettingsTileView mUserTile; - private RefreshCallback mUserCallback; - private UserState mUserState = new UserState(); - - private QuickSettingsTileView mTimeTile; - private RefreshCallback mTimeCallback; - private State mTimeState = new State(); - - private QuickSettingsTileView mAlarmTile; - private RefreshCallback mAlarmCallback; - private State mAlarmState = new State(); - - private QuickSettingsTileView mAirplaneModeTile; - private RefreshCallback mAirplaneModeCallback; - private State mAirplaneModeState = new State(); - - private QuickSettingsTileView mZenModeTile; - private RefreshCallback mZenModeCallback; - private ZenModeState mZenModeState = new ZenModeState(); - - private QuickSettingsTileView mWifiTile; - private RefreshCallback mWifiCallback; - private WifiState mWifiState = new WifiState(); - - private QuickSettingsTileView mRemoteDisplayTile; - private RefreshCallback mRemoteDisplayCallback; - private State mRemoteDisplayState = new State(); - - private QuickSettingsTileView mRSSITile; - private RefreshCallback mRSSICallback; - private RSSIState mRSSIState = new RSSIState(); - - private QuickSettingsTileView mBluetoothTile; - private RefreshCallback mBluetoothCallback; - private BluetoothState mBluetoothState = new BluetoothState(); - - private QuickSettingsTileView mBatteryTile; - private RefreshCallback mBatteryCallback; - private BatteryState mBatteryState = new BatteryState(); - - private QuickSettingsTileView mLocationTile; - private RefreshCallback mLocationCallback; - private State mLocationState = new State(); - - private QuickSettingsTileView mImeTile; - private RefreshCallback mImeCallback = null; - private State mImeState = new State(); - - private QuickSettingsTileView mRotationLockTile; - private RefreshCallback mRotationLockCallback; - private RotationLockState mRotationLockState = new RotationLockState(); - - private QuickSettingsTileView mBrightnessTile; - private RefreshCallback mBrightnessCallback; - private BrightnessState mBrightnessState = new BrightnessState(); - - private QuickSettingsTileView mInversionTile; - private RefreshCallback mInversionCallback; - private InversionState mInversionState = new InversionState(); - - private QuickSettingsTileView mColorSpaceTile; - private RefreshCallback mColorSpaceCallback; - private ColorSpaceState mColorSpaceState = new ColorSpaceState(); - - private QuickSettingsTileView mBugreportTile; - private RefreshCallback mBugreportCallback; - private State mBugreportState = new State(); - - private QuickSettingsTileView mSettingsTile; - private RefreshCallback mSettingsCallback; - private State mSettingsState = new State(); - - private QuickSettingsTileView mSslCaCertWarningTile; - private RefreshCallback mSslCaCertWarningCallback; - private State mSslCaCertWarningState = new State(); - - private RotationLockController mRotationLockController; - private int mRotationLockedLabel; - - public QuickSettingsModel(Context context) { - mContext = context; - mHandler = new Handler(); - mUserTracker = new CurrentUserTracker(mContext) { - @Override - public void onUserSwitched(int newUserId) { - mBrightnessObserver.startObserving(); - mInversionObserver.startObserving(); - mColorSpaceObserver.startObserving(); - refreshRotationLockTile(); - onBrightnessLevelChanged(); - onInversionChanged(); - onColorSpaceChanged(); - onNextAlarmChanged(); - onBugreportChanged(); - rebindMediaRouterAsCurrentUser(); - } - }; - mUserTracker.startTracking(); - - mNextAlarmObserver = new NextAlarmObserver(mHandler); - mNextAlarmObserver.startObserving(); - mBugreportObserver = new BugreportObserver(mHandler); - mBugreportObserver.startObserving(); - mBrightnessObserver = new BrightnessObserver(mHandler); - mBrightnessObserver.startObserving(); - mInversionObserver = new DisplayInversionObserver(mHandler); - mInversionObserver.startObserving(); - mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler); - mColorSpaceObserver.startObserving(); - mZenModeObserver = new ZenModeObserver(mHandler); - mZenModeObserver.startObserving(); - - mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE); - rebindMediaRouterAsCurrentUser(); - - mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback(); - - ConnectivityManager cm = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); - - IntentFilter alarmIntentFilter = new IntentFilter(); - alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED); - context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter); - } - - void updateResources() { - refreshSettingsTile(); - refreshBatteryTile(); - refreshBluetoothTile(); - refreshBrightnessTile(); - refreshRotationLockTile(); - refreshRssiTile(); - refreshLocationTile(); - } - - // Settings - void addSettingsTile(QuickSettingsTileView view, RefreshCallback cb) { - mSettingsTile = view; - mSettingsCallback = cb; - refreshSettingsTile(); - } - void refreshSettingsTile() { - Resources r = mContext.getResources(); - mSettingsState.label = r.getString(R.string.quick_settings_settings_label); - mSettingsCallback.refreshView(mSettingsTile, mSettingsState); - } - - // User - void addUserTile(QuickSettingsTileView view, RefreshCallback cb) { - mUserTile = view; - mUserCallback = cb; - mUserCallback.refreshView(mUserTile, mUserState); - } - void setUserTileInfo(String name, Drawable avatar) { - mUserState.label = name; - mUserState.avatar = avatar; - mUserCallback.refreshView(mUserTile, mUserState); - } - - // Time - void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) { - mTimeTile = view; - mTimeCallback = cb; - mTimeCallback.refreshView(view, mTimeState); - } - - // Alarm - void addAlarmTile(QuickSettingsTileView view, RefreshCallback cb) { - mAlarmTile = view; - mAlarmCallback = cb; - mAlarmCallback.refreshView(view, mAlarmState); - } - void onAlarmChanged(Intent intent) { - mAlarmState.enabled = intent.getBooleanExtra("alarmSet", false); - mAlarmCallback.refreshView(mAlarmTile, mAlarmState); - } - void onNextAlarmChanged() { - final String alarmText = Settings.System.getStringForUser(mContext.getContentResolver(), - Settings.System.NEXT_ALARM_FORMATTED, - UserHandle.USER_CURRENT); - mAlarmState.label = alarmText; - - // When switching users, this is the only clue we're going to get about whether the - // alarm is actually set, since we won't get the ACTION_ALARM_CHANGED broadcast - mAlarmState.enabled = ! TextUtils.isEmpty(alarmText); - - mAlarmCallback.refreshView(mAlarmTile, mAlarmState); - } - - // Airplane Mode - void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) { - mAirplaneModeTile = view; - mAirplaneModeTile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mAirplaneModeState.enabled) { - setAirplaneModeState(false); - } else { - setAirplaneModeState(true); - } - } - }); - mAirplaneModeCallback = cb; - int airplaneMode = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0); - onAirplaneModeChanged(airplaneMode != 0); - } - private void setAirplaneModeState(boolean enabled) { - // TODO: Sets the view to be "awaiting" if not already awaiting - - // Change the system setting - Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, - enabled ? 1 : 0); - - // Post the intent - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", enabled); - mContext.sendBroadcast(intent); - } - // NetworkSignalChanged callback - @Override - public void onAirplaneModeChanged(boolean enabled) { - // TODO: If view is in awaiting state, disable - Resources r = mContext.getResources(); - mAirplaneModeState.enabled = enabled; - mAirplaneModeState.iconId = (enabled ? - R.drawable.ic_qs_airplane_on : - R.drawable.ic_qs_airplane_off); - mAirplaneModeState.label = r.getString(R.string.quick_settings_airplane_mode_label); - mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); - } - - // Zen Mode - void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) { - mZenModeTile = view; - mZenModeCallback = cb; - onZenModeChanged(); - } - private void onZenModeChanged() { - final int mode = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); - mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF; - mZenModeState.zenMode = mode; - mZenModeState.label = mContext.getString(R.string.zen_mode_title); - mZenModeState.iconId = R.drawable.stat_sys_zen_limited; - mZenModeCallback.refreshView(mZenModeTile, mZenModeState); - } - - // Wifi - void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) { - mWifiTile = view; - mWifiCallback = cb; - mWifiCallback.refreshView(mWifiTile, mWifiState); - } - // Remove the double quotes that the SSID may contain - public static String removeDoubleQuotes(String string) { - if (string == null) return null; - final int length = string.length(); - if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { - return string.substring(1, length - 1); - } - return string; - } - // Remove the period from the network name - public static String removeTrailingPeriod(String string) { - if (string == null) return null; - final int length = string.length(); - if (string.endsWith(".")) { - return string.substring(0, length - 1); - } - return string; - } - // NetworkSignalChanged callback - @Override - public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, - boolean activityIn, boolean activityOut, - String wifiSignalContentDescription, String enabledDesc) { - // TODO: If view is in awaiting state, disable - Resources r = mContext.getResources(); - - boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null); - boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null); - mWifiState.enabled = enabled; - mWifiState.connected = wifiConnected; - mWifiState.activityIn = enabled && activityIn; - mWifiState.activityOut = enabled && activityOut; - if (wifiConnected) { - mWifiState.iconId = wifiSignalIconId; - mWifiState.label = removeDoubleQuotes(enabledDesc); - mWifiState.signalContentDescription = wifiSignalContentDescription; - } else if (wifiNotConnected) { - mWifiState.iconId = R.drawable.ic_qs_wifi_0; - mWifiState.label = r.getString(R.string.quick_settings_wifi_label); - mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi); - } else { - mWifiState.iconId = R.drawable.ic_qs_wifi_no_network; - mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label); - mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off); - } - mWifiCallback.refreshView(mWifiTile, mWifiState); - } - - boolean deviceHasMobileData() { - return mHasMobileData; - } - - // RSSI - void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) { - mRSSITile = view; - mRSSICallback = cb; - mRSSICallback.refreshView(mRSSITile, mRSSIState); - } - // NetworkSignalChanged callback - @Override - public void onMobileDataSignalChanged( - boolean enabled, int mobileSignalIconId, String signalContentDescription, - int dataTypeIconId, boolean activityIn, boolean activityOut, - String dataContentDescription,String enabledDesc) { - if (deviceHasMobileData()) { - // TODO: If view is in awaiting state, disable - Resources r = mContext.getResources(); - mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0) - ? mobileSignalIconId - : R.drawable.ic_qs_signal_no_signal; - mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0) - ? signalContentDescription - : r.getString(R.string.accessibility_no_signal); - mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled - ? dataTypeIconId - : 0; - mRSSIState.activityIn = enabled && activityIn; - mRSSIState.activityOut = enabled && activityOut; - mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled - ? dataContentDescription - : r.getString(R.string.accessibility_no_data); - mRSSIState.label = enabled - ? removeTrailingPeriod(enabledDesc) - : r.getString(R.string.quick_settings_rssi_emergency_only); - mRSSICallback.refreshView(mRSSITile, mRSSIState); - } - } - - void refreshRssiTile() { - if (mRSSITile != null) { - // We reinflate the original view due to potential styling changes that may have - // taken place due to a configuration change. - mRSSITile.reinflateContent(LayoutInflater.from(mContext)); - } - } - - // Bluetooth - void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) { - mBluetoothTile = view; - mBluetoothCallback = cb; - - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - mBluetoothState.enabled = adapter.isEnabled(); - mBluetoothState.connected = - (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED); - onBluetoothStateChange(mBluetoothState); - } - boolean deviceSupportsBluetooth() { - return (BluetoothAdapter.getDefaultAdapter() != null); - } - // BluetoothController callback - @Override - public void onBluetoothStateChange(boolean on) { - mBluetoothState.enabled = on; - onBluetoothStateChange(mBluetoothState); - } - public void onBluetoothStateChange(BluetoothState bluetoothStateIn) { - // TODO: If view is in awaiting state, disable - Resources r = mContext.getResources(); - mBluetoothState.enabled = bluetoothStateIn.enabled; - mBluetoothState.connected = bluetoothStateIn.connected; - if (mBluetoothState.enabled) { - if (mBluetoothState.connected) { - mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on; - mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected); - } else { - mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected; - mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on); - } - mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label); - } else { - mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off; - mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label); - mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off); - } - mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState); - } - void refreshBluetoothTile() { - if (mBluetoothTile != null) { - onBluetoothStateChange(mBluetoothState.enabled); - } - } - - // Battery - void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) { - mBatteryTile = view; - mBatteryCallback = cb; - mBatteryCallback.refreshView(mBatteryTile, mBatteryState); - } - // BatteryController callback - @Override - public void onBatteryLevelChanged(int level, boolean pluggedIn) { - mBatteryState.batteryLevel = level; - mBatteryState.pluggedIn = pluggedIn; - mBatteryCallback.refreshView(mBatteryTile, mBatteryState); - } - void refreshBatteryTile() { - mBatteryCallback.refreshView(mBatteryTile, mBatteryState); - } - - // Location - void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) { - mLocationTile = view; - mLocationCallback = cb; - mLocationCallback.refreshView(mLocationTile, mLocationState); - } - - void refreshLocationTile() { - if (mLocationTile != null) { - onLocationSettingsChanged(mLocationState.enabled); - } - } - - @Override - public void onLocationSettingsChanged(boolean locationEnabled) { - int textResId = locationEnabled ? R.string.quick_settings_location_label - : R.string.quick_settings_location_off_label; - String label = mContext.getText(textResId).toString(); - int locationIconId = locationEnabled - ? R.drawable.ic_qs_location_on : R.drawable.ic_qs_location_off; - mLocationState.enabled = locationEnabled; - mLocationState.label = label; - mLocationState.iconId = locationIconId; - mLocationCallback.refreshView(mLocationTile, mLocationState); - } - - // Bug report - void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) { - mBugreportTile = view; - mBugreportCallback = cb; - onBugreportChanged(); - } - // SettingsObserver callback - public void onBugreportChanged() { - final ContentResolver cr = mContext.getContentResolver(); - boolean enabled = false; - try { - enabled = (Settings.Global.getInt(cr, Settings.Global.BUGREPORT_IN_POWER_MENU) != 0); - } catch (SettingNotFoundException e) { - } - - mBugreportState.enabled = enabled && mUserTracker.isCurrentUserOwner(); - mBugreportCallback.refreshView(mBugreportTile, mBugreportState); - } - - // Remote Display - void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) { - mRemoteDisplayTile = view; - mRemoteDisplayCallback = cb; - mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() { - @Override - public void onPrepare() { - mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, - mRemoteDisplayRouteCallback, - MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); - updateRemoteDisplays(); - } - @Override - public void onUnprepare() { - mMediaRouter.removeCallback(mRemoteDisplayRouteCallback); - } - }); - - updateRemoteDisplays(); - } - - private void rebindMediaRouterAsCurrentUser() { - mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId()); - } - - private void updateRemoteDisplays() { - MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute( - MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); - boolean enabled = connectedRoute != null - && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); - boolean connecting; - if (enabled) { - connecting = connectedRoute.isConnecting(); - } else { - connectedRoute = null; - connecting = false; - enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, - MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE); - } - - mRemoteDisplayState.enabled = enabled; - if (connectedRoute != null) { - mRemoteDisplayState.label = connectedRoute.getName().toString(); - mRemoteDisplayState.iconId = connecting ? - R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected; - } else { - mRemoteDisplayState.label = mContext.getString( - R.string.quick_settings_remote_display_no_connection_label); - mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available; - } - mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState); - } - - // IME - void addImeTile(QuickSettingsTileView view, RefreshCallback cb) { - mImeTile = view; - mImeCallback = cb; - mImeCallback.refreshView(mImeTile, mImeState); - } - /* This implementation is taken from - InputMethodManagerService.needsToShowImeSwitchOngoingNotification(). */ - private boolean needsToShowImeSwitchOngoingNotification(InputMethodManager imm) { - List<InputMethodInfo> imis = imm.getEnabledInputMethodList(); - final int N = imis.size(); - if (N > 2) return true; - if (N < 1) return false; - int nonAuxCount = 0; - int auxCount = 0; - InputMethodSubtype nonAuxSubtype = null; - InputMethodSubtype auxSubtype = null; - for(int i = 0; i < N; ++i) { - final InputMethodInfo imi = imis.get(i); - final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(imi, - true); - final int subtypeCount = subtypes.size(); - if (subtypeCount == 0) { - ++nonAuxCount; - } else { - for (int j = 0; j < subtypeCount; ++j) { - final InputMethodSubtype subtype = subtypes.get(j); - if (!subtype.isAuxiliary()) { - ++nonAuxCount; - nonAuxSubtype = subtype; - } else { - ++auxCount; - auxSubtype = subtype; - } - } - } - } - if (nonAuxCount > 1 || auxCount > 1) { - return true; - } else if (nonAuxCount == 1 && auxCount == 1) { - if (nonAuxSubtype != null && auxSubtype != null - && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale()) - || auxSubtype.overridesImplicitlyEnabledSubtype() - || nonAuxSubtype.overridesImplicitlyEnabledSubtype()) - && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) { - return false; - } - return true; - } - return false; - } - void onImeWindowStatusChanged(boolean visible) { - InputMethodManager imm = - (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); - List<InputMethodInfo> imis = imm.getInputMethodList(); - - mImeState.enabled = (visible && needsToShowImeSwitchOngoingNotification(imm)); - mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(), - imm, imis, mContext.getPackageManager()); - if (mImeCallback != null) { - mImeCallback.refreshView(mImeTile, mImeState); - } - } - private static String getCurrentInputMethodName(Context context, ContentResolver resolver, - InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) { - if (resolver == null || imis == null) return null; - final String currentInputMethodId = Settings.Secure.getString(resolver, - Settings.Secure.DEFAULT_INPUT_METHOD); - if (TextUtils.isEmpty(currentInputMethodId)) return null; - for (InputMethodInfo imi : imis) { - if (currentInputMethodId.equals(imi.getId())) { - final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype(); - final CharSequence summary = subtype != null - ? subtype.getDisplayName(context, imi.getPackageName(), - imi.getServiceInfo().applicationInfo) - : context.getString(R.string.quick_settings_ime_label); - return summary.toString(); - } - } - return null; - } - - // Rotation lock - void addRotationLockTile(QuickSettingsTileView view, - RotationLockController rotationLockController, - RefreshCallback cb) { - mRotationLockTile = view; - mRotationLockCallback = cb; - mRotationLockController = rotationLockController; - final int lockOrientation = mRotationLockController.getRotationLockOrientation(); - mRotationLockedLabel = lockOrientation == Configuration.ORIENTATION_PORTRAIT - ? R.string.quick_settings_rotation_locked_portrait_label - : lockOrientation == Configuration.ORIENTATION_LANDSCAPE - ? R.string.quick_settings_rotation_locked_landscape_label - : R.string.quick_settings_rotation_locked_label; - onRotationLockChanged(); - } - void onRotationLockChanged() { - onRotationLockStateChanged(mRotationLockController.isRotationLocked(), - mRotationLockController.isRotationLockAffordanceVisible()); - } - @Override - public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { - mRotationLockState.visible = affordanceVisible; - mRotationLockState.enabled = rotationLocked; - mRotationLockState.iconId = rotationLocked - ? R.drawable.ic_qs_rotation_locked - : R.drawable.ic_qs_auto_rotate; - mRotationLockState.label = rotationLocked - ? mContext.getString(mRotationLockedLabel) - : mContext.getString(R.string.quick_settings_rotation_unlocked_label); - mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState); - } - void refreshRotationLockTile() { - if (mRotationLockTile != null) { - onRotationLockChanged(); - } - } - - // Brightness - void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) { - mBrightnessTile = view; - mBrightnessCallback = cb; - onBrightnessLevelChanged(); - } - @Override - public void onBrightnessLevelChanged() { - Resources r = mContext.getResources(); - int mode = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, - mUserTracker.getCurrentUserId()); - mBrightnessState.autoBrightness = - (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - mBrightnessState.iconId = mBrightnessState.autoBrightness - ? R.drawable.ic_qs_brightness_auto_on - : R.drawable.ic_qs_brightness_auto_off; - mBrightnessState.label = r.getString(R.string.quick_settings_brightness_label); - mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState); - } - void refreshBrightnessTile() { - onBrightnessLevelChanged(); - } - - // Color inversion - void addInversionTile(QuickSettingsTileView view, RefreshCallback cb) { - mInversionTile = view; - mInversionCallback = cb; - onInversionChanged(); - } - public void onInversionChanged() { - final Resources res = mContext.getResources(); - final ContentResolver cr = mContext.getContentResolver(); - final int currentUserId = mUserTracker.getCurrentUserId(); - final boolean quickSettingEnabled = Settings.Secure.getIntForUser( - cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED, 0, - currentUserId) == 1; - final boolean enabled = Settings.Secure.getIntForUser( - cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId) == 1; - mInversionState.enabled = quickSettingEnabled; - mInversionState.toggled = enabled; - // TODO: Add real icon assets. - mInversionState.iconId = enabled ? R.drawable.ic_qs_inversion_on - : R.drawable.ic_qs_inversion_off; - mInversionState.label = res.getString(R.string.quick_settings_inversion_label); - mInversionCallback.refreshView(mInversionTile, mInversionState); - } - - // Color space adjustment - void addColorSpaceTile(QuickSettingsTileView view, RefreshCallback cb) { - mColorSpaceTile = view; - mColorSpaceCallback = cb; - onColorSpaceChanged(); - } - public void onColorSpaceChanged() { - final Resources res = mContext.getResources(); - final ContentResolver cr = mContext.getContentResolver(); - final int currentUserId = mUserTracker.getCurrentUserId(); - final boolean quickSettingEnabled = Settings.Secure.getIntForUser( - cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED, 0, - currentUserId) == 1; - final boolean enabled = Settings.Secure.getIntForUser(cr, - Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, currentUserId) == 1; - final int type = Settings.Secure.getIntForUser( - cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, 0, currentUserId); - mColorSpaceState.enabled = quickSettingEnabled; - mColorSpaceState.toggled = enabled; - mColorSpaceState.type = type; - // TODO: Add real icon assets. - mColorSpaceState.iconId = enabled ? R.drawable.ic_qs_color_space_on - : R.drawable.ic_qs_color_space_off; - mColorSpaceState.label = res.getString(R.string.quick_settings_color_space_label); - mColorSpaceCallback.refreshView(mColorSpaceTile, mColorSpaceState); - } - - // SSL CA Cert warning. - public void addSslCaCertWarningTile(QuickSettingsTileView view, RefreshCallback cb) { - mSslCaCertWarningTile = view; - mSslCaCertWarningCallback = cb; - // Set a sane default while we wait for the AsyncTask to finish (no cert). - setSslCaCertWarningTileInfo(false, true); - } - public void setSslCaCertWarningTileInfo(boolean hasCert, boolean isManaged) { - Resources r = mContext.getResources(); - mSslCaCertWarningState.enabled = hasCert; - if (isManaged) { - mSslCaCertWarningState.iconId = R.drawable.ic_qs_certificate_info; - } else { - mSslCaCertWarningState.iconId = android.R.drawable.stat_notify_error; - } - mSslCaCertWarningState.label = r.getString(R.string.ssl_ca_cert_warning); - mSslCaCertWarningCallback.refreshView(mSslCaCertWarningTile, mSslCaCertWarningState); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java deleted file mode 100644 index 175805a..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ScrollView; - -public class QuickSettingsScrollView extends ScrollView { - - public QuickSettingsScrollView(Context context) { - super(context); - } - - public QuickSettingsScrollView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public QuickSettingsScrollView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - // Y U NO PROTECTED - private int getScrollRange() { - int scrollRange = 0; - if (getChildCount() > 0) { - View child = getChildAt(0); - scrollRange = Math.max(0, - child.getHeight() - (getHeight() - getPaddingBottom() - getPaddingTop())); - } - return scrollRange; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - final int range = getScrollRange(); - if (range == 0) { - return false; - } - - return super.onTouchEvent(ev); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java deleted file mode 100644 index ad18294..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewParent; -import android.widget.FrameLayout; - -/** - * - */ -class QuickSettingsTileView extends FrameLayout { - private static final String TAG = "QuickSettingsTileView"; - - private int mContentLayoutId; - private int mColSpan; - private boolean mPrepared; - private OnPrepareListener mOnPrepareListener; - - public QuickSettingsTileView(Context context, AttributeSet attrs) { - super(context, attrs); - - mContentLayoutId = -1; - mColSpan = 1; - } - - void setColumnSpan(int span) { - mColSpan = span; - } - - int getColumnSpan() { - return mColSpan; - } - - void setContent(int layoutId, LayoutInflater inflater) { - mContentLayoutId = layoutId; - inflater.inflate(layoutId, this); - } - - void reinflateContent(LayoutInflater inflater) { - if (mContentLayoutId != -1) { - removeAllViews(); - setContent(mContentLayoutId, inflater); - } else { - Log.e(TAG, "Not reinflating content: No layoutId set"); - } - } - - @Override - public void setVisibility(int vis) { - if (QuickSettings.DEBUG_GONE_TILES) { - if (vis == View.GONE) { - vis = View.VISIBLE; - setAlpha(0.25f); - setEnabled(false); - } else { - setAlpha(1f); - setEnabled(true); - } - } - super.setVisibility(vis); - } - - public void setOnPrepareListener(OnPrepareListener listener) { - if (mOnPrepareListener != listener) { - mOnPrepareListener = listener; - mPrepared = false; - post(new Runnable() { - @Override - public void run() { - updatePreparedState(); - } - }); - } - } - - @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - updatePreparedState(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - updatePreparedState(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - updatePreparedState(); - } - - private void updatePreparedState() { - if (mOnPrepareListener != null) { - if (isParentVisible()) { - if (!mPrepared) { - mPrepared = true; - mOnPrepareListener.onPrepare(); - } - } else if (mPrepared) { - mPrepared = false; - mOnPrepareListener.onUnprepare(); - } - } - } - - private boolean isParentVisible() { - if (!isAttachedToWindow()) { - return false; - } - for (ViewParent current = getParent(); current instanceof View; - current = current.getParent()) { - View view = (View)current; - if (view.getVisibility() != VISIBLE) { - return false; - } - } - return true; - } - - /** - * Called when the view's parent becomes visible or invisible to provide - * an opportunity for the client to provide new content. - */ - public interface OnPrepareListener { - void onPrepare(); - void onUnprepare(); - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 5527473..2305445 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -28,6 +28,7 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.android.systemui.R; +import com.android.systemui.qs.QSPanel; import com.android.systemui.settings.BrightnessController; import com.android.systemui.settings.ToggleSlider; import com.android.systemui.statusbar.policy.UserInfoController; @@ -60,6 +61,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private ActivityStarter mActivityStarter; private BrightnessController mBrightnessController; + private QSPanel mQSPanel; private final Rect mClipBounds = new Rect(); private final Outline mOutline = new Outline(); @@ -115,6 +117,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateVisibilities(); updateSystemIconsLayoutParams(); updateBrightnessControllerState(); + if (mQSPanel != null) { + mQSPanel.setExpanded(expanded); + } } } @@ -259,4 +264,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private void startSettingsActivity() { mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS)); } + + public void setQSPanel(QSPanel qsp) { + mQSPanel = qsp; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java deleted file mode 100644 index ff921cd..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.graphics.PorterDuff.Mode; -import android.graphics.Typeface; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.OvalShape; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.TextPaint; -import android.text.method.LinkMovementMethod; -import android.text.style.URLSpan; -import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.Switch; -import android.widget.TextView; -import android.widget.Toast; - -import com.android.systemui.R; -import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition; - -public class ZenModeView extends RelativeLayout { - private static final String TAG = ZenModeView.class.getSimpleName(); - private static final boolean DEBUG = false; - - public static final int BACKGROUND = 0xff282828; - - private static final Typeface CONDENSED = - Typeface.create("sans-serif-condensed", Typeface.NORMAL); - private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network - private static final int DARK_GRAY = 0xff333333; - - private static final long DURATION = new ValueAnimator().getDuration(); - private static final long PAGER_DURATION = DURATION / 2; - private static final long CLOSE_DELAY = 600; - private static final long AUTO_ACTIVATE_DELAY = 100; - - private final Context mContext; - private final TextView mModeText; - private final Switch mModeSwitch; - private final View mDivider; - private final UntilPager mUntilPager; - private final ProgressDots mProgressDots; - private final View mDivider2; - private final TextView mSettingsButton; - - private Adapter mAdapter; - private boolean mInit; - private boolean mAutoActivate; - - public ZenModeView(Context context) { - this(context, null); - } - - public ZenModeView(Context context, AttributeSet attrs) { - super(context, attrs); - if (DEBUG) log("new %s()", getClass().getSimpleName()); - mContext = context; - - final int iconSize = mContext.getResources() - .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width); - final int topRowSize = iconSize * 2 / 3; - final int p = topRowSize / 3; - - LayoutParams lp = null; - - mModeText = new TextView(mContext); - mModeText.setText(R.string.zen_mode_title); - mModeText.setId(android.R.id.title); - mModeText.setTextColor(GRAY); - mModeText.setTypeface(CONDENSED); - mModeText.setAllCaps(true); - mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); - mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f); - lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize); - lp.leftMargin = p; - addView(mModeText, lp); - - mModeSwitch = new Switch(mContext); - mModeSwitch.setSwitchPadding(0); - mModeSwitch.setSwitchTypeface(CONDENSED); - lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize); - lp.topMargin = p; - lp.rightMargin = p; - lp.addRule(ALIGN_PARENT_RIGHT); - lp.addRule(ALIGN_BASELINE, mModeText.getId()); - addView(mModeSwitch, lp); - mModeSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - mAdapter.setMode(isChecked); - if (!mInit) return; - postDelayed(new Runnable(){ - @Override - public void run() { - mAdapter.close(); - } - }, CLOSE_DELAY); - } - }); - - mDivider = new View(mContext); - mDivider.setId(android.R.id.empty); - mDivider.setBackgroundColor(GRAY); - lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2); - lp.addRule(BELOW, mModeText.getId()); - lp.bottomMargin = p; - addView(mDivider, lp); - - mUntilPager = new UntilPager(mContext, iconSize * 3 / 4); - mUntilPager.setId(android.R.id.tabhost); - lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - lp.leftMargin = lp.rightMargin = iconSize / 2; - lp.addRule(CENTER_HORIZONTAL); - lp.addRule(BELOW, mDivider.getId()); - addView(mUntilPager, lp); - - mProgressDots = new ProgressDots(mContext, iconSize / 5); - mProgressDots.setId(android.R.id.progress); - lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - lp.addRule(CENTER_HORIZONTAL); - lp.addRule(BELOW, mUntilPager.getId()); - addView(mProgressDots, lp); - - mDivider2 = new View(mContext); - mDivider2.setId(android.R.id.widget_frame); - mDivider2.setBackgroundColor(GRAY); - lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2); - lp.addRule(BELOW, mProgressDots.getId()); - addView(mDivider2, lp); - - mSettingsButton = new TextView(mContext); - mSettingsButton.setTypeface(CONDENSED); - mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f); - mSettingsButton.setPadding(p, p, p, p); - mSettingsButton.setText("More settings..."); - lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - lp.addRule(BELOW, mDivider2.getId()); - addView(mSettingsButton, lp); - mSettingsButton.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - mSettingsButton.setBackgroundColor(DARK_GRAY); - } else if (event.getAction() == MotionEvent.ACTION_UP) { - mSettingsButton.setBackground(null); - if (mAdapter != null) { - mAdapter.configure(); - } - } - return true; - } - }); - } - - public void setAdapter(Adapter adapter) { - mAdapter = adapter; - mAdapter.setCallbacks(new Adapter.Callbacks() { - @Override - public void onChanged() { - post(new Runnable() { - @Override - public void run() { - updateState(true); - } - }); - } - }); - updateState(false); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (mAutoActivate) { - mAutoActivate = false; - postDelayed(new Runnable() { - @Override - public void run() { - if (!mModeSwitch.isChecked()) { - mInit = false; - mModeSwitch.setChecked(true); - } - } - }, AUTO_ACTIVATE_DELAY); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mAdapter != null) { - mAdapter.dispose(); - } - } - - public void setAutoActivate(boolean value) { - mAutoActivate = value; - } - - private void updateState(boolean animate) { - mUntilPager.updateState(); - mModeSwitch.setChecked(mAdapter.getMode()); - mInit = true; - } - - private static void log(String msg, Object... args) { - Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args)); - } - - private final class UntilView extends FrameLayout { - private static final boolean SUPPORT_LINKS = false; - - private final TextView mText; - public UntilView(Context context) { - super(context); - mText = new TextView(mContext); - mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f); - mText.setTypeface(CONDENSED); - mText.setTextColor(GRAY); - mText.setGravity(Gravity.CENTER); - addView(mText); - } - - public void setExitCondition(final ExitCondition ec) { - SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary); - if (SUPPORT_LINKS && ec.action != null) { - ss.setSpan(new CustomLinkSpan() { - @Override - public void onClick() { - // TODO wire up links - Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show(); - } - }, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - mText.setMovementMethod(LinkMovementMethod.getInstance()); - } else { - mText.setMovementMethod(null); - } - mText.setText(ss); - } - } - - private final class ProgressDots extends LinearLayout { - private final int mDotSize; - public ProgressDots(Context context, int dotSize) { - super(context); - setOrientation(HORIZONTAL); - mDotSize = dotSize; - } - - private void updateState(int current, int count) { - while (getChildCount() < count) { - View dot = new View(mContext); - OvalShape s = new OvalShape(); - ShapeDrawable sd = new ShapeDrawable(s); - - dot.setBackground(sd); - LayoutParams lp = new LayoutParams(mDotSize, mDotSize); - lp.leftMargin = lp.rightMargin = mDotSize / 2; - lp.topMargin = lp.bottomMargin = mDotSize * 2 / 3; - addView(dot, lp); - } - while (getChildCount() > count) { - removeViewAt(getChildCount() - 1); - } - final int N = getChildCount(); - for (int i = 0; i < N; i++) { - final int color = current == i ? GRAY : DARK_GRAY; - ((ShapeDrawable)getChildAt(i).getBackground()).setColorFilter(color, Mode.ADD); - } - } - } - - private final class UntilPager extends RelativeLayout { - private final UntilView[] mViews; - private int mCurrent; - private float mDownX; - - public UntilPager(Context context, int iconSize) { - super(context); - mViews = new UntilView[3]; - for (int i = 0; i < mViews.length; i++) { - UntilView v = new UntilView(mContext); - LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, iconSize); - addView(v, lp); - mViews[i] = v; - } - updateState(); - addOnLayoutChangeListener(new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, - int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - if (left != oldLeft || right != oldRight) { - updateState(); - } - } - }); - setBackgroundColor(DARK_GRAY); - } - - private void updateState() { - if (mAdapter == null) { - return; - } - UntilView current = mViews[mCurrent]; - current.setExitCondition(mAdapter.getExitCondition(0)); - UntilView next = mViews[mCurrent + 1 % 3]; - next.setExitCondition(mAdapter.getExitCondition(1)); - UntilView prev = mViews[mCurrent + 2 % 3]; - prev.setExitCondition(mAdapter.getExitCondition(-1)); - position(0, false); - mProgressDots.updateState(mAdapter.getExitConditionIndex(), - mAdapter.getExitConditionCount()); - } - - private void position(float dx, boolean animate) { - int w = getWidth(); - UntilView current = mViews[mCurrent]; - UntilView next = mViews[mCurrent + 1 % 3]; - UntilView prev = mViews[mCurrent + 2 % 3]; - if (animate) { - current.animate().setDuration(PAGER_DURATION).translationX(dx).start(); - next.animate().setDuration(PAGER_DURATION).translationX(w + dx).start(); - prev.animate().setDuration(PAGER_DURATION).translationX(-w + dx).start(); - } else { - current.setTranslationX(dx); - next.setTranslationX(w + dx); - prev.setTranslationX(-w + dx); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (DEBUG) log("onTouchEvent " + MotionEvent.actionToString(event.getAction())); - if (event.getAction() == MotionEvent.ACTION_DOWN) { - mDownX = event.getX(); - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - float dx = event.getX() - mDownX; - position(dx, false); - } else if (event.getAction() == MotionEvent.ACTION_UP - || event.getAction() == MotionEvent.ACTION_CANCEL) { - float dx = event.getX() - mDownX; - int d = Math.abs(dx) < getWidth() / 3 ? 0 : Math.signum(dx) > 0 ? -1 : 1; - if (d != 0 && mAdapter.getExitConditionCount() > 1) { - mAdapter.select(mAdapter.getExitCondition(d)); - } else { - position(0, true); - } - } - return true; - } - } - - private abstract static class CustomLinkSpan extends URLSpan { - abstract public void onClick(); - - public CustomLinkSpan() { - super("#"); - } - - @Override - public void updateDrawState(TextPaint ds) { - super.updateDrawState(ds); - ds.setUnderlineText(false); - ds.bgColor = BACKGROUND; - } - - @Override - public void onClick(View widget) { - onClick(); - } - } - - public interface Adapter { - void configure(); - void close(); - boolean getMode(); - void setMode(boolean mode); - void select(ExitCondition ec); - void init(); - void dispose(); - void setCallbacks(Callbacks callbacks); - ExitCondition getExitCondition(int d); - int getExitConditionCount(); - int getExitConditionIndex(); - - public static class ExitCondition { - public String summary; - public String line1; - public String line2; - public String action; - public Object tag; - } - - public interface Callbacks { - void onChanged(); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java deleted file mode 100644 index 8748888..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.app.INotificationManager; -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.service.notification.Condition; -import android.service.notification.IConditionListener; -import android.util.ArrayMap; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { - private static final String TAG = "ZenModeViewAdapter"; - - private final Context mContext; - private final ContentResolver mResolver; - private final Handler mHandler = new Handler(); - private final SettingsObserver mObserver; - private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList( - newExit("Until you turn this off", "Until", "You turn this off", null))); - private final INotificationManager mNoMan; - private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>(); - - private Callbacks mCallbacks; - private int mExitIndex; - private boolean mMode; - - public ZenModeViewAdapter(Context context) { - mContext = context; - mResolver = mContext.getContentResolver(); - mObserver = new SettingsObserver(mHandler); - mNoMan = INotificationManager.Stub.asInterface( - ServiceManager.getService(Context.NOTIFICATION_SERVICE)); - try { - mNoMan.requestZenModeConditions(mListener, Condition.FLAG_RELEVANT_NOW); - } catch (RemoteException e) { - // noop - } - mObserver.init(); - init(); - } - - @Override - public boolean getMode() { - return mMode; - } - - @Override - public void setMode(boolean mode) { - if (mode == mMode) return; - mMode = mode; - final int v = mMode ? Settings.Global.ZEN_MODE_ON : Settings.Global.ZEN_MODE_OFF; - AsyncTask.execute(new Runnable() { - @Override - public void run() { - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.ZEN_MODE, v); - } - }); - dispatchChanged(); - } - - @Override - public void init() { - if (mExitIndex != 0) { - mExitIndex = 0; - dispatchChanged(); - } - setZenModeCondition(); - } - - @Override - public void dispose() { - try { - mNoMan.requestZenModeConditions(mListener, 0 /*none*/); - } catch (RemoteException e) { - // noop - } - } - - private void dispatchChanged() { - mHandler.removeCallbacks(mChanged); - mHandler.post(mChanged); - } - - @Override - public void setCallbacks(final Callbacks callbacks) { - mHandler.post(new Runnable() { - @Override - public void run() { - mCallbacks = callbacks; - } - }); - } - - @Override - public ExitCondition getExitCondition(int d) { - final int n = mExits.size(); - final int i = (n + (mExitIndex + (int)Math.signum(d))) % n; - return mExits.get(i); - } - - @Override - public int getExitConditionCount() { - return mExits.size(); - } - - @Override - public int getExitConditionIndex() { - return mExitIndex; - } - - @Override - public void select(ExitCondition ec) { - final int i = mExits.indexOf(ec); - if (i == -1 || i == mExitIndex) { - return; - } - mExitIndex = i; - dispatchChanged(); - setZenModeCondition(); - } - - private void setZenModeCondition() { - if (mExitIndex < 0 || mExitIndex >= mExits.size()) { - Log.w(TAG, "setZenModeCondition to bad index " + mExitIndex + " of " + mExits.size()); - return; - } - final Uri conditionUri = (Uri) mExits.get(mExitIndex).tag; - try { - mNoMan.setZenModeCondition(conditionUri); - } catch (RemoteException e) { - // noop - } - } - - private static ExitCondition newExit(String summary, String line1, String line2, Object tag) { - final ExitCondition rt = new ExitCondition(); - rt.summary = summary; - rt.line1 = line1; - rt.line2 = line2; - rt.tag = tag; - return rt; - } - - private final Runnable mChanged = new Runnable() { - public void run() { - if (mCallbacks == null) { - return; - } - try { - mCallbacks.onChanged(); - } catch (Throwable t) { - Log.w(TAG, "Error dispatching onChanged to " + mCallbacks, t); - } - } - }; - - private final class SettingsObserver extends ContentObserver { - public SettingsObserver(Handler handler) { - super(handler); - } - - public void init() { - loadSettings(); - mResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ZEN_MODE), - false, this); - } - - @Override - public void onChange(boolean selfChange) { - loadSettings(); - mChanged.run(); // already on handler - } - - private void loadSettings() { - mMode = getModeFromSetting(); - } - - private boolean getModeFromSetting() { - final int v = Settings.Global.getInt(mResolver, - Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); - return v != Settings.Global.ZEN_MODE_OFF; - } - } - - private final IConditionListener mListener = new IConditionListener.Stub() { - @Override - public void onConditionsReceived(Condition[] conditions) { - if (conditions == null || conditions.length == 0) return; - for (Condition c : conditions) { - mConditions.put(c.id, c); - } - for (int i = mExits.size() - 1; i > 0; i--) { - mExits.remove(i); - } - for (Condition c : mConditions.values()) { - mExits.add(newExit(c.summary, c.line1, c.line2, c.id)); - } - dispatchChanged(); - } - }; -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java index 0e53f0d..f4145cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,87 +16,14 @@ package com.android.systemui.statusbar.policy; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; +public interface BluetoothController { + void addStateChangedCallback(BluetoothStateChangeCallback callback); + void removeStateChangedCallback(BluetoothStateChangeCallback callback); -public class BluetoothController extends BroadcastReceiver { - private static final String TAG = "StatusBar.BluetoothController"; - - private boolean mEnabled = false; - - private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>(); - - private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks = - new ArrayList<BluetoothStateChangeCallback>(); - - public BluetoothController(Context context) { - - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); - filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); - context.registerReceiver(this, filter); - - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - handleAdapterStateChange(adapter.getState()); - } - fireCallbacks(); - updateBondedBluetoothDevices(); - } - - public void addStateChangedCallback(BluetoothStateChangeCallback cb) { - mChangeCallbacks.add(cb); - } - - public Set<BluetoothDevice> getBondedBluetoothDevices() { - return mBondedDevices; - } - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - - if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { - handleAdapterStateChange( - intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)); - } - fireCallbacks(); - updateBondedBluetoothDevices(); - } - - private void updateBondedBluetoothDevices() { - mBondedDevices.clear(); - - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - Set<BluetoothDevice> devices = adapter.getBondedDevices(); - if (devices != null) { - for (BluetoothDevice device : devices) { - if (device.getBondState() != BluetoothDevice.BOND_NONE) { - mBondedDevices.add(device); - } - } - } - } - } - - private void handleAdapterStateChange(int adapterState) { - mEnabled = (adapterState == BluetoothAdapter.STATE_ON); - } - - private void fireCallbacks() { - for (BluetoothStateChangeCallback cb : mChangeCallbacks) { - cb.onBluetoothStateChange(mEnabled); - } - } + boolean isBluetoothSupported(); + boolean isBluetoothEnabled(); + boolean isBluetoothConnected(); + void setBluetoothEnabled(boolean enabled); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java new file mode 100644 index 0000000..1c7119f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class BluetoothControllerImpl extends BroadcastReceiver implements BluetoothController { + private static final String TAG = "StatusBar.BluetoothController"; + + private final BluetoothAdapter mAdapter; + + private boolean mEnabled = false; + + private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>(); + + private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks = + new ArrayList<BluetoothStateChangeCallback>(); + + public BluetoothControllerImpl(Context context) { + mAdapter = BluetoothAdapter.getDefaultAdapter(); + + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); + filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + context.registerReceiver(this, filter); + + final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + handleAdapterStateChange(adapter.getState()); + } + fireCallbacks(); + updateBondedBluetoothDevices(); + } + + public void addStateChangedCallback(BluetoothStateChangeCallback cb) { + mChangeCallbacks.add(cb); + } + + @Override + public void removeStateChangedCallback(BluetoothStateChangeCallback cb) { + mChangeCallbacks.remove(cb); + } + + @Override + public boolean isBluetoothEnabled() { + return mAdapter != null && mAdapter.isEnabled(); + } + + @Override + public boolean isBluetoothConnected() { + return mAdapter != null + && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED; + } + + @Override + public void setBluetoothEnabled(boolean enabled) { + if (mAdapter != null) { + if (enabled) { + mAdapter.enable(); + } else { + mAdapter.disable(); + } + } + } + + @Override + public boolean isBluetoothSupported() { + return mAdapter != null; + } + + public Set<BluetoothDevice> getBondedBluetoothDevices() { + return mBondedDevices; + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { + handleAdapterStateChange( + intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)); + } + fireCallbacks(); + updateBondedBluetoothDevices(); + } + + private void updateBondedBluetoothDevices() { + mBondedDevices.clear(); + + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + Set<BluetoothDevice> devices = adapter.getBondedDevices(); + if (devices != null) { + for (BluetoothDevice device : devices) { + if (device.getBondState() != BluetoothDevice.BOND_NONE) { + mBondedDevices.add(device); + } + } + } + } + } + + private void handleAdapterStateChange(int adapterState) { + mEnabled = (adapterState == BluetoothAdapter.STATE_ON); + } + + private void fireCallbacks() { + for (BluetoothStateChangeCallback cb : mChangeCallbacks) { + cb.onBluetoothStateChange(mEnabled); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java new file mode 100644 index 0000000..54041e1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +public interface CastController { + void addCallback(Callback callback); + void removeCallback(Callback callback); + void setDiscovering(boolean request); + void setCurrentUserId(int currentUserId); + + public interface Callback { + void onStateChanged(boolean enabled, boolean connecting, String connectedRouteName); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java new file mode 100644 index 0000000..33a85b1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.content.Context; +import android.media.MediaRouter; +import android.media.MediaRouter.RouteInfo; + +import java.util.ArrayList; + +/** Platform implementation of the cast controller. **/ +public class CastControllerImpl implements CastController { + + private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); + private final MediaRouter mMediaRouter; + + public CastControllerImpl(Context context) { + mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); + } + + @Override + public void addCallback(Callback callback) { + mCallbacks.add(callback); + } + + @Override + public void removeCallback(Callback callback) { + mCallbacks.remove(callback); + } + + @Override + public void setDiscovering(boolean request) { + if (request) { + mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, + mMediaCallback, + MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); + } else { + mMediaRouter.removeCallback(mMediaCallback); + } + } + + @Override + public void setCurrentUserId(int currentUserId) { + mMediaRouter.rebindAsUser(currentUserId); + } + + private void updateRemoteDisplays() { + final MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute( + MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); + boolean enabled = connectedRoute != null + && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); + boolean connecting; + if (enabled) { + connecting = connectedRoute.isConnecting(); + } else { + connecting = false; + enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, + MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE); + } + + String connectedRouteName = null; + if (connectedRoute != null) { + connectedRouteName = connectedRoute.getName().toString(); + } + fireStateChanged(enabled, connecting, connectedRouteName); + } + + private void fireStateChanged(boolean enabled, boolean connecting, String connectedRouteName) { + for (Callback callback : mCallbacks) { + callback.onStateChanged(enabled, connecting, connectedRouteName); + } + } + + private final MediaRouter.SimpleCallback mMediaCallback = new MediaRouter.SimpleCallback() { + @Override + public void onRouteAdded(MediaRouter router, RouteInfo route) { + updateRemoteDisplays(); + } + @Override + public void onRouteChanged(MediaRouter router, RouteInfo route) { + updateRemoteDisplays(); + } + @Override + public void onRouteRemoved(MediaRouter router, RouteInfo route) { + updateRemoteDisplays(); + } + @Override + public void onRouteSelected(MediaRouter router, int type, RouteInfo route) { + updateRemoteDisplays(); + } + @Override + public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) { + updateRemoteDisplays(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java new file mode 100644 index 0000000..158e9c1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +/** Common interface for items requiring manual cleanup. **/ +public interface Disposable { + void dispose(); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index f5ee95b..29a8981 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,47 +16,11 @@ package com.android.systemui.statusbar.policy; -import android.app.ActivityManager; -import android.app.AppOpsManager; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.location.LocationManager; -import android.os.Handler; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.Settings; - -import com.android.systemui.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * A controller to manage changes of location related states and update the views accordingly. - */ -public class LocationController extends BroadcastReceiver { - // The name of the placeholder corresponding to the location request status icon. - // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml. - public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location"; - public static final int LOCATION_STATUS_ICON_ID - = R.drawable.stat_sys_device_access_location_found; - - private static final int[] mHighPowerRequestAppOpArray - = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION}; - - private Context mContext; - - private AppOpsManager mAppOpsManager; - private StatusBarManager mStatusBarManager; - - private boolean mAreActiveLocationRequests; - - private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks = - new ArrayList<LocationSettingsChangeCallback>(); +public interface LocationController { + boolean isLocationEnabled(); + boolean setLocationEnabled(boolean enabled); + void addSettingsChangedCallback(LocationSettingsChangeCallback cb); + void removeSettingsChangedCallback(LocationSettingsChangeCallback cb); /** * A callback for change in location settings (the user has enabled/disabled location). @@ -68,156 +32,6 @@ public class LocationController extends BroadcastReceiver { * @param locationEnabled A value of true indicates that at least one type of location * is enabled in settings. */ - public void onLocationSettingsChanged(boolean locationEnabled); - } - - public LocationController(Context context) { - mContext = context; - - IntentFilter filter = new IntentFilter(); - filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); - context.registerReceiver(this, filter); - - mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - mStatusBarManager - = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); - - // Register to listen for changes in location settings. - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION); - context.registerReceiverAsUser(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (LocationManager.MODE_CHANGED_ACTION.equals(action)) { - locationSettingsChanged(); - } - } - }, UserHandle.ALL, intentFilter, null, new Handler()); - - // Examine the current location state and initialize the status view. - updateActiveLocationRequests(); - refreshViews(); - } - - /** - * Add a callback to listen for changes in location settings. - */ - public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) { - mSettingsChangeCallbacks.add(cb); - } - - /** - * Enable or disable location in settings. - * - * <p>This will attempt to enable/disable every type of location setting - * (e.g. high and balanced power). - * - * <p>If enabling, a user consent dialog will pop up prompting the user to accept. - * If the user doesn't accept, network location won't be enabled. - * - * @return true if attempt to change setting was successful. - */ - public boolean setLocationEnabled(boolean enabled) { - int currentUserId = ActivityManager.getCurrentUser(); - if (isUserLocationRestricted(currentUserId)) { - return false; - } - final ContentResolver cr = mContext.getContentResolver(); - // When enabling location, a user consent dialog will pop up, and the - // setting won't be fully enabled until the user accepts the agreement. - int mode = enabled - ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF; - // QuickSettings always runs as the owner, so specifically set the settings - // for the current foreground user. - return Settings.Secure - .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId); - } - - /** - * Returns true if location isn't disabled in settings. - */ - public boolean isLocationEnabled() { - ContentResolver resolver = mContext.getContentResolver(); - // QuickSettings always runs as the owner, so specifically retrieve the settings - // for the current foreground user. - int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE, - Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser()); - return mode != Settings.Secure.LOCATION_MODE_OFF; - } - - /** - * Returns true if the current user is restricted from using location. - */ - private boolean isUserLocationRestricted(int userId) { - final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - return um.hasUserRestriction( - UserManager.DISALLOW_SHARE_LOCATION, - new UserHandle(userId)); - } - - /** - * Returns true if there currently exist active high power location requests. - */ - private boolean areActiveHighPowerLocationRequests() { - List<AppOpsManager.PackageOps> packages - = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray); - // AppOpsManager can return null when there is no requested data. - if (packages != null) { - final int numPackages = packages.size(); - for (int packageInd = 0; packageInd < numPackages; packageInd++) { - AppOpsManager.PackageOps packageOp = packages.get(packageInd); - List<AppOpsManager.OpEntry> opEntries = packageOp.getOps(); - if (opEntries != null) { - final int numOps = opEntries.size(); - for (int opInd = 0; opInd < numOps; opInd++) { - AppOpsManager.OpEntry opEntry = opEntries.get(opInd); - // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because - // of the mHighPowerRequestAppOpArray filter, but checking defensively. - if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) { - if (opEntry.isRunning()) { - return true; - } - } - } - } - } - } - - return false; - } - - // Updates the status view based on the current state of location requests. - private void refreshViews() { - if (mAreActiveLocationRequests) { - mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0, - mContext.getString(R.string.accessibility_location_active)); - } else { - mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER); - } - } - - // Reads the active location requests and updates the status view if necessary. - private void updateActiveLocationRequests() { - boolean hadActiveLocationRequests = mAreActiveLocationRequests; - mAreActiveLocationRequests = areActiveHighPowerLocationRequests(); - if (mAreActiveLocationRequests != hadActiveLocationRequests) { - refreshViews(); - } - } - - private void locationSettingsChanged() { - boolean isEnabled = isLocationEnabled(); - for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) { - cb.onLocationSettingsChanged(isEnabled); - } - } - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) { - updateActiveLocationRequests(); - } + void onLocationSettingsChanged(boolean locationEnabled); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java new file mode 100644 index 0000000..9e5ad18 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.location.LocationManager; +import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; + +import com.android.systemui.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * A controller to manage changes of location related states and update the views accordingly. + */ +public class LocationControllerImpl extends BroadcastReceiver implements LocationController { + // The name of the placeholder corresponding to the location request status icon. + // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml. + public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location"; + public static final int LOCATION_STATUS_ICON_ID + = R.drawable.stat_sys_device_access_location_found; + + private static final int[] mHighPowerRequestAppOpArray + = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION}; + + private Context mContext; + + private AppOpsManager mAppOpsManager; + private StatusBarManager mStatusBarManager; + + private boolean mAreActiveLocationRequests; + + private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks = + new ArrayList<LocationSettingsChangeCallback>(); + + public LocationControllerImpl(Context context) { + mContext = context; + + IntentFilter filter = new IntentFilter(); + filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); + context.registerReceiver(this, filter); + + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mStatusBarManager + = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); + + // Register to listen for changes in location settings. + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION); + context.registerReceiverAsUser(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (LocationManager.MODE_CHANGED_ACTION.equals(action)) { + locationSettingsChanged(); + } + } + }, UserHandle.ALL, intentFilter, null, new Handler()); + + // Examine the current location state and initialize the status view. + updateActiveLocationRequests(); + refreshViews(); + } + + /** + * Add a callback to listen for changes in location settings. + */ + public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) { + mSettingsChangeCallbacks.add(cb); + } + + public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) { + mSettingsChangeCallbacks.remove(cb); + } + + /** + * Enable or disable location in settings. + * + * <p>This will attempt to enable/disable every type of location setting + * (e.g. high and balanced power). + * + * <p>If enabling, a user consent dialog will pop up prompting the user to accept. + * If the user doesn't accept, network location won't be enabled. + * + * @return true if attempt to change setting was successful. + */ + public boolean setLocationEnabled(boolean enabled) { + int currentUserId = ActivityManager.getCurrentUser(); + if (isUserLocationRestricted(currentUserId)) { + return false; + } + final ContentResolver cr = mContext.getContentResolver(); + // When enabling location, a user consent dialog will pop up, and the + // setting won't be fully enabled until the user accepts the agreement. + int mode = enabled + ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF; + // QuickSettings always runs as the owner, so specifically set the settings + // for the current foreground user. + return Settings.Secure + .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId); + } + + /** + * Returns true if location isn't disabled in settings. + */ + public boolean isLocationEnabled() { + ContentResolver resolver = mContext.getContentResolver(); + // QuickSettings always runs as the owner, so specifically retrieve the settings + // for the current foreground user. + int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE, + Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser()); + return mode != Settings.Secure.LOCATION_MODE_OFF; + } + + /** + * Returns true if the current user is restricted from using location. + */ + private boolean isUserLocationRestricted(int userId) { + final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + return um.hasUserRestriction( + UserManager.DISALLOW_SHARE_LOCATION, + new UserHandle(userId)); + } + + /** + * Returns true if there currently exist active high power location requests. + */ + private boolean areActiveHighPowerLocationRequests() { + List<AppOpsManager.PackageOps> packages + = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray); + // AppOpsManager can return null when there is no requested data. + if (packages != null) { + final int numPackages = packages.size(); + for (int packageInd = 0; packageInd < numPackages; packageInd++) { + AppOpsManager.PackageOps packageOp = packages.get(packageInd); + List<AppOpsManager.OpEntry> opEntries = packageOp.getOps(); + if (opEntries != null) { + final int numOps = opEntries.size(); + for (int opInd = 0; opInd < numOps; opInd++) { + AppOpsManager.OpEntry opEntry = opEntries.get(opInd); + // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because + // of the mHighPowerRequestAppOpArray filter, but checking defensively. + if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) { + if (opEntry.isRunning()) { + return true; + } + } + } + } + } + } + + return false; + } + + // Updates the status view based on the current state of location requests. + private void refreshViews() { + if (mAreActiveLocationRequests) { + mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0, + mContext.getString(R.string.accessibility_location_active)); + } else { + mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER); + } + } + + // Reads the active location requests and updates the status view if necessary. + private void updateActiveLocationRequests() { + boolean hadActiveLocationRequests = mAreActiveLocationRequests; + mAreActiveLocationRequests = areActiveHighPowerLocationRequests(); + if (mAreActiveLocationRequests != hadActiveLocationRequests) { + refreshViews(); + } + } + + private void locationSettingsChanged() { + boolean isEnabled = isLocationEnabled(); + for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) { + cb.onLocationSettingsChanged(isEnabled); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) { + updateActiveLocationRequests(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 92c008e..dc8f315 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,153 +16,12 @@ package com.android.systemui.statusbar.policy; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wimax.WimaxManagerConstants; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.provider.Settings; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.view.View; -import android.widget.TextView; +public interface NetworkController { -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.cdma.EriInfo; -import com.android.internal.util.AsyncChannel; -import com.android.systemui.DemoMode; -import com.android.systemui.R; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class NetworkController extends BroadcastReceiver implements DemoMode { - // debug - static final String TAG = "StatusBar.NetworkController"; - static final boolean DEBUG = false; - static final boolean CHATTY = false; // additional diagnostics, but not logspew - - private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode; - - // telephony - boolean mHspaDataDistinguishable; - final TelephonyManager mPhone; - boolean mDataConnected; - IccCardConstants.State mSimState = IccCardConstants.State.READY; - int mPhoneState = TelephonyManager.CALL_STATE_IDLE; - int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - int mDataState = TelephonyManager.DATA_DISCONNECTED; - int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; - ServiceState mServiceState; - SignalStrength mSignalStrength; - int[] mDataIconList = TelephonyIcons.DATA_G[0]; - String mNetworkName; - String mNetworkNameDefault; - String mNetworkNameSeparator; - int mPhoneSignalIconId; - int mQSPhoneSignalIconId; - int mDataDirectionIconId; // data + data direction on phones - int mDataSignalIconId; - int mDataTypeIconId; - int mQSDataTypeIconId; - int mAirplaneIconId; - boolean mDataActive; - int mLastSignalLevel; - boolean mShowPhoneRSSIForData = false; - boolean mShowAtLeastThreeGees = false; - boolean mAlwaysShowCdmaRssi = false; - - String mContentDescriptionPhoneSignal; - String mContentDescriptionWifi; - String mContentDescriptionWimax; - String mContentDescriptionCombinedSignal; - String mContentDescriptionDataType; - - // wifi - final WifiManager mWifiManager; - AsyncChannel mWifiChannel; - boolean mWifiEnabled, mWifiConnected; - int mWifiRssi, mWifiLevel; - String mWifiSsid; - int mWifiIconId = 0; - int mQSWifiIconId = 0; - int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE; - - // bluetooth - private boolean mBluetoothTethered = false; - private int mBluetoothTetherIconId = - com.android.internal.R.drawable.stat_sys_tether_bluetooth; - - //wimax - private boolean mWimaxSupported = false; - private boolean mIsWimaxEnabled = false; - private boolean mWimaxConnected = false; - private boolean mWimaxIdle = false; - private int mWimaxIconId = 0; - private int mWimaxSignal = 0; - private int mWimaxState = 0; - private int mWimaxExtraState = 0; - - // data connectivity (regardless of state, can we access the internet?) - // state of inet connection - 0 not connected, 100 connected - private boolean mConnected = false; - private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE; - private String mConnectedNetworkTypeName; - private int mInetCondition = 0; - private int mLastInetCondition = 0; - private static final int INET_CONDITION_THRESHOLD = 50; - - private boolean mAirplaneMode = false; - private boolean mLastAirplaneMode = true; - - private Locale mLocale = null; - private Locale mLastLocale = null; - - // our ui - Context mContext; - ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>(); - ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>(); - ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>(); - ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>(); - ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>(); - ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks = - new ArrayList<NetworkSignalChangedCallback>(); - int mLastPhoneSignalIconId = -1; - int mLastDataDirectionIconId = -1; - int mLastWifiIconId = -1; - int mLastWimaxIconId = -1; - int mLastCombinedSignalIconId = -1; - int mLastDataTypeIconId = -1; - String mLastCombinedLabel = ""; - - private boolean mHasMobileDataFeature; - - boolean mDataAndWifiStacked = false; - - public interface SignalCluster { - void setWifiIndicators(boolean visible, int strengthIcon, boolean problem, - String contentDescription); - void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem, - int typeIcon, String contentDescription, String typeContentDescription); - void setIsAirplaneMode(boolean is, int airplaneIcon); - } + boolean hasMobileDataFeature(); + void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb); + void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb); + void setWifiEnabled(boolean enabled); public interface NetworkSignalChangedCallback { void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, @@ -174,1304 +33,4 @@ public class NetworkController extends BroadcastReceiver implements DemoMode { String dataTypeContentDescriptionId, String description); void onAirplaneModeChanged(boolean enabled); } - - /** - * Construct this controller object and register for updates. - */ - public NetworkController(Context context) { - mContext = context; - final Resources res = context.getResources(); - - ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); - - mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData); - mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G); - mAlwaysShowCdmaRssi = res.getBoolean( - com.android.internal.R.bool.config_alwaysUseCdmaRssi); - - // set up the default wifi icon, used when no radios have ever appeared - updateWifiIcons(); - updateWimaxIcons(); - - // telephony - mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - mPhone.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_SERVICE_STATE - | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS - | PhoneStateListener.LISTEN_CALL_STATE - | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE - | PhoneStateListener.LISTEN_DATA_ACTIVITY); - mHspaDataDistinguishable = mContext.getResources().getBoolean( - R.bool.config_hspa_data_distinguishable); - mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator); - mNetworkNameDefault = mContext.getString( - com.android.internal.R.string.lockscreen_carrier_default); - mNetworkName = mNetworkNameDefault; - - // wifi - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - Handler handler = new WifiHandler(); - mWifiChannel = new AsyncChannel(); - Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger(); - if (wifiMessenger != null) { - mWifiChannel.connect(mContext, handler, wifiMessenger); - } - - // broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.RSSI_CHANGED_ACTION); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); - mWimaxSupported = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_wimaxEnabled); - if(mWimaxSupported) { - filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION); - filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION); - } - context.registerReceiver(this, filter); - - // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it - updateAirplaneMode(); - - mLastLocale = mContext.getResources().getConfiguration().locale; - } - - public boolean hasMobileDataFeature() { - return mHasMobileDataFeature; - } - - public boolean hasVoiceCallingFeature() { - return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; - } - - public boolean isEmergencyOnly() { - return (mServiceState != null && mServiceState.isEmergencyOnly()); - } - - public void addCombinedLabelView(TextView v) { - mCombinedLabelViews.add(v); - } - - public void addMobileLabelView(TextView v) { - mMobileLabelViews.add(v); - } - - public void addWifiLabelView(TextView v) { - mWifiLabelViews.add(v); - } - - public void addEmergencyLabelView(TextView v) { - mEmergencyLabelViews.add(v); - } - - public void addSignalCluster(SignalCluster cluster) { - mSignalClusters.add(cluster); - refreshSignalCluster(cluster); - } - - public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) { - mSignalsChangedCallbacks.add(cb); - notifySignalsChangedCallbacks(cb); - } - - public void refreshSignalCluster(SignalCluster cluster) { - if (mDemoMode) return; - cluster.setWifiIndicators( - // only show wifi in the cluster if connected or if wifi-only - mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature), - mWifiIconId, - mInetCondition == 0, - mContentDescriptionWifi); - - if (mIsWimaxEnabled && mWimaxConnected) { - // wimax is special - cluster.setMobileDataIndicators( - true, - mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId, - mInetCondition == 0, - mDataTypeIconId, - mContentDescriptionWimax, - mContentDescriptionDataType); - } else { - // normal mobile data - cluster.setMobileDataIndicators( - mHasMobileDataFeature, - mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId, - mInetCondition == 0, - mDataTypeIconId, - mContentDescriptionPhoneSignal, - mContentDescriptionDataType); - } - cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId); - } - - void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) { - // only show wifi in the cluster if connected or if wifi-only - boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature); - String wifiDesc = wifiEnabled ? - mWifiSsid : null; - boolean wifiIn = wifiEnabled && mWifiSsid != null - && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT - || mWifiActivity == WifiManager.DATA_ACTIVITY_IN); - boolean wifiOut = wifiEnabled && mWifiSsid != null - && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT - || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT); - cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut, - mContentDescriptionWifi, wifiDesc); - - boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT - || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN); - boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT - || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT); - if (isEmergencyOnly()) { - cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId, - mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, - mContentDescriptionDataType, null); - } else { - if (mIsWimaxEnabled && mWimaxConnected) { - // Wimax is special - cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId, - mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, - mContentDescriptionDataType, mNetworkName); - } else { - // Normal mobile data - cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId, - mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, - mContentDescriptionDataType, mNetworkName); - } - } - cb.onAirplaneModeChanged(mAirplaneMode); - } - - public void setStackedMode(boolean stacked) { - mDataAndWifiStacked = true; - } - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.RSSI_CHANGED_ACTION) - || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) - || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - updateWifiState(intent); - refreshViews(); - } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { - updateSimState(intent); - updateDataIcon(); - refreshViews(); - } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { - updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), - intent.getStringExtra(TelephonyIntents.EXTRA_SPN), - intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), - intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); - refreshViews(); - } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || - action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { - updateConnectivity(intent); - refreshViews(); - } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { - refreshLocale(); - refreshViews(); - } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { - refreshLocale(); - updateAirplaneMode(); - refreshViews(); - } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) || - action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) || - action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { - updateWimaxState(intent); - refreshViews(); - } - } - - - // ===== Telephony ============================================================== - - PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - if (DEBUG) { - Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + - ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); - } - mSignalStrength = signalStrength; - updateTelephonySignalStrength(); - refreshViews(); - } - - @Override - public void onServiceStateChanged(ServiceState state) { - if (DEBUG) { - Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState() - + " dataState=" + state.getDataRegState()); - } - mServiceState = state; - updateTelephonySignalStrength(); - updateDataNetType(); - updateDataIcon(); - refreshViews(); - } - - @Override - public void onCallStateChanged(int state, String incomingNumber) { - if (DEBUG) { - Log.d(TAG, "onCallStateChanged state=" + state); - } - // In cdma, if a voice call is made, RSSI should switch to 1x. - if (isCdma()) { - updateTelephonySignalStrength(); - refreshViews(); - } - } - - @Override - public void onDataConnectionStateChanged(int state, int networkType) { - if (DEBUG) { - Log.d(TAG, "onDataConnectionStateChanged: state=" + state - + " type=" + networkType); - } - mDataState = state; - mDataNetType = networkType; - updateDataNetType(); - updateDataIcon(); - refreshViews(); - } - - @Override - public void onDataActivity(int direction) { - if (DEBUG) { - Log.d(TAG, "onDataActivity: direction=" + direction); - } - mDataActivity = direction; - updateDataIcon(); - refreshViews(); - } - }; - - private final void updateSimState(Intent intent) { - String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); - if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { - mSimState = IccCardConstants.State.ABSENT; - } - else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { - mSimState = IccCardConstants.State.READY; - } - else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { - final String lockedReason = - intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); - if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - mSimState = IccCardConstants.State.PIN_REQUIRED; - } - else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - mSimState = IccCardConstants.State.PUK_REQUIRED; - } - else { - mSimState = IccCardConstants.State.NETWORK_LOCKED; - } - } else { - mSimState = IccCardConstants.State.UNKNOWN; - } - } - - private boolean isCdma() { - return (mSignalStrength != null) && !mSignalStrength.isGsm(); - } - - private boolean hasService() { - if (mServiceState != null) { - // Consider the device to be in service if either voice or data service is available. - // Some SIM cards are marketed as data-only and do not support voice service, and on - // these SIM cards, we want to show signal bars for data service as well as the "no - // service" or "emergency calls only" text that indicates that voice is not available. - switch(mServiceState.getVoiceRegState()) { - case ServiceState.STATE_POWER_OFF: - return false; - case ServiceState.STATE_OUT_OF_SERVICE: - case ServiceState.STATE_EMERGENCY_ONLY: - return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; - default: - return true; - } - } else { - return false; - } - } - - private void updateAirplaneMode() { - mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1); - } - - private void refreshLocale() { - mLocale = mContext.getResources().getConfiguration().locale; - } - - private final void updateTelephonySignalStrength() { - if (!hasService()) { - if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()"); - mPhoneSignalIconId = R.drawable.stat_sys_signal_null; - mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; - mDataSignalIconId = R.drawable.stat_sys_signal_null; - } else { - if (mSignalStrength == null) { - if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null"); - mPhoneSignalIconId = R.drawable.stat_sys_signal_null; - mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; - mDataSignalIconId = R.drawable.stat_sys_signal_null; - mContentDescriptionPhoneSignal = mContext.getString( - AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]); - } else { - int iconLevel; - int[] iconList; - if (isCdma() && mAlwaysShowCdmaRssi) { - mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel(); - if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi - + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel() - + " instead of level=" + mSignalStrength.getLevel()); - } else { - mLastSignalLevel = iconLevel = mSignalStrength.getLevel(); - } - - if (isCdma()) { - if (isCdmaEri()) { - iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; - } else { - iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; - } - } else { - // Though mPhone is a Manager, this call is not an IPC - if (mPhone.isNetworkRoaming()) { - iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; - } else { - iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; - } - } - mPhoneSignalIconId = iconList[iconLevel]; - mQSPhoneSignalIconId = - TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel]; - mContentDescriptionPhoneSignal = mContext.getString( - AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]); - mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; - } - } - } - - private final void updateDataNetType() { - if (mIsWimaxEnabled && mWimaxConnected) { - // wimax is a special 4g network not handled by telephony - mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_4g); - } else { - switch (mDataNetType) { - case TelephonyManager.NETWORK_TYPE_UNKNOWN: - if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; - mDataTypeIconId = 0; - mQSDataTypeIconId = 0; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_gprs); - break; - } else { - // fall through - } - case TelephonyManager.NETWORK_TYPE_EDGE: - if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_E[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_edge); - break; - } else { - // fall through - } - case TelephonyManager.NETWORK_TYPE_UMTS: - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_3g); - break; - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - if (mHspaDataDistinguishable) { - mDataIconList = TelephonyIcons.DATA_H[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_3_5g); - } else { - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_3g); - } - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - if (!mShowAtLeastThreeGees) { - // display 1xRTT for IS95A/B - mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_cdma); - break; - } else { - // fall through - } - case TelephonyManager.NETWORK_TYPE_1xRTT: - if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_cdma); - break; - } else { - // fall through - } - case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - case TelephonyManager.NETWORK_TYPE_EHRPD: - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_3g); - break; - case TelephonyManager.NETWORK_TYPE_LTE: - boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE); - if (show4GforLTE) { - mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_4g); - } else { - mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_lte); - } - break; - default: - if (!mShowAtLeastThreeGees) { - mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_gprs); - } else { - mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; - mContentDescriptionDataType = mContext.getString( - R.string.accessibility_data_connection_3g); - } - break; - } - } - - if (isCdma()) { - if (isCdmaEri()) { - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; - } - } else if (mPhone.isNetworkRoaming()) { - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; - } - } - - boolean isCdmaEri() { - if (mServiceState != null) { - final int iconIndex = mServiceState.getCdmaEriIconIndex(); - if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { - final int iconMode = mServiceState.getCdmaEriIconMode(); - if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL - || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { - return true; - } - } - } - return false; - } - - private final void updateDataIcon() { - int iconId; - boolean visible = true; - - if (!isCdma()) { - // GSM case, we have to check also the sim state - if (mSimState == IccCardConstants.State.READY || - mSimState == IccCardConstants.State.UNKNOWN) { - if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { - switch (mDataActivity) { - case TelephonyManager.DATA_ACTIVITY_IN: - iconId = mDataIconList[1]; - break; - case TelephonyManager.DATA_ACTIVITY_OUT: - iconId = mDataIconList[2]; - break; - case TelephonyManager.DATA_ACTIVITY_INOUT: - iconId = mDataIconList[3]; - break; - default: - iconId = mDataIconList[0]; - break; - } - mDataDirectionIconId = iconId; - } else { - iconId = 0; - visible = false; - } - } else { - iconId = R.drawable.stat_sys_no_sim; - visible = false; // no SIM? no data - } - } else { - // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT - if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { - switch (mDataActivity) { - case TelephonyManager.DATA_ACTIVITY_IN: - iconId = mDataIconList[1]; - break; - case TelephonyManager.DATA_ACTIVITY_OUT: - iconId = mDataIconList[2]; - break; - case TelephonyManager.DATA_ACTIVITY_INOUT: - iconId = mDataIconList[3]; - break; - case TelephonyManager.DATA_ACTIVITY_DORMANT: - default: - iconId = mDataIconList[0]; - break; - } - } else { - iconId = 0; - visible = false; - } - } - - mDataDirectionIconId = iconId; - mDataConnected = visible; - } - - void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { - if (false) { - Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn - + " showPlmn=" + showPlmn + " plmn=" + plmn); - } - StringBuilder str = new StringBuilder(); - boolean something = false; - if (showPlmn && plmn != null) { - str.append(plmn); - something = true; - } - if (showSpn && spn != null) { - if (something) { - str.append(mNetworkNameSeparator); - } - str.append(spn); - something = true; - } - if (something) { - mNetworkName = str.toString(); - } else { - mNetworkName = mNetworkNameDefault; - } - } - - // ===== Wifi =================================================================== - - class WifiHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - mWifiChannel.sendMessage(Message.obtain(this, - AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); - } else { - Log.e(TAG, "Failed to connect to wifi"); - } - break; - case WifiManager.DATA_ACTIVITY_NOTIFICATION: - if (msg.arg1 != mWifiActivity) { - mWifiActivity = msg.arg1; - refreshViews(); - } - break; - default: - //Ignore - break; - } - } - } - - private void updateWifiState(Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - boolean wasConnected = mWifiConnected; - mWifiConnected = networkInfo != null && networkInfo.isConnected(); - // If we just connected, grab the inintial signal strength and ssid - if (mWifiConnected && !wasConnected) { - // try getting it out of the intent first - WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); - if (info == null) { - info = mWifiManager.getConnectionInfo(); - } - if (info != null) { - mWifiSsid = huntForSsid(info); - } else { - mWifiSsid = null; - } - } else if (!mWifiConnected) { - mWifiSsid = null; - } - } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { - mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); - mWifiLevel = WifiManager.calculateSignalLevel( - mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT); - } - - updateWifiIcons(); - } - - private void updateWifiIcons() { - if (mWifiConnected) { - mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; - mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; - mContentDescriptionWifi = mContext.getString( - AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]); - } else { - if (mDataAndWifiStacked) { - mWifiIconId = 0; - mQSWifiIconId = 0; - } else { - mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0; - mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0; - } - mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi); - } - } - - private String huntForSsid(WifiInfo info) { - String ssid = info.getSSID(); - if (ssid != null) { - return ssid; - } - // OK, it's not in the connectionInfo; we have to go hunting for it - List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); - for (WifiConfiguration net : networks) { - if (net.networkId == info.getNetworkId()) { - return net.SSID; - } - } - return null; - } - - - // ===== Wimax =================================================================== - private final void updateWimaxState(Intent intent) { - final String action = intent.getAction(); - boolean wasConnected = mWimaxConnected; - if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) { - int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE, - WimaxManagerConstants.NET_4G_STATE_UNKNOWN); - mIsWimaxEnabled = (wimaxStatus == - WimaxManagerConstants.NET_4G_STATE_ENABLED); - } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) { - mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0); - } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { - mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE, - WimaxManagerConstants.NET_4G_STATE_UNKNOWN); - mWimaxExtraState = intent.getIntExtra( - WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL, - WimaxManagerConstants.NET_4G_STATE_UNKNOWN); - mWimaxConnected = (mWimaxState == - WimaxManagerConstants.WIMAX_STATE_CONNECTED); - mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE); - } - updateDataNetType(); - updateWimaxIcons(); - } - - private void updateWimaxIcons() { - if (mIsWimaxEnabled) { - if (mWimaxConnected) { - if (mWimaxIdle) - mWimaxIconId = WimaxIcons.WIMAX_IDLE; - else - mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal]; - mContentDescriptionWimax = mContext.getString( - AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]); - } else { - mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED; - mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax); - } - } else { - mWimaxIconId = 0; - } - } - - // ===== Full or limited Internet connectivity ================================== - - private void updateConnectivity(Intent intent) { - if (CHATTY) { - Log.d(TAG, "updateConnectivity: intent=" + intent); - } - - final ConnectivityManager connManager = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); - final NetworkInfo info = connManager.getActiveNetworkInfo(); - - // Are we connected at all, by any interface? - mConnected = info != null && info.isConnected(); - if (mConnected) { - mConnectedNetworkType = info.getType(); - mConnectedNetworkTypeName = info.getTypeName(); - } else { - mConnectedNetworkType = ConnectivityManager.TYPE_NONE; - mConnectedNetworkTypeName = null; - } - - int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); - - if (CHATTY) { - Log.d(TAG, "updateConnectivity: networkInfo=" + info); - Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus); - } - - mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); - - if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) { - mBluetoothTethered = info.isConnected(); - } else { - mBluetoothTethered = false; - } - - // We want to update all the icons, all at once, for any condition change - updateDataNetType(); - updateWimaxIcons(); - updateDataIcon(); - updateTelephonySignalStrength(); - updateWifiIcons(); - } - - - // ===== Update the views ======================================================= - - void refreshViews() { - Context context = mContext; - - int combinedSignalIconId = 0; - String combinedLabel = ""; - String wifiLabel = ""; - String mobileLabel = ""; - int N; - final boolean emergencyOnly = isEmergencyOnly(); - - if (!mHasMobileDataFeature) { - mDataSignalIconId = mPhoneSignalIconId = 0; - mQSPhoneSignalIconId = 0; - mobileLabel = ""; - } else { - // We want to show the carrier name if in service and either: - // - We are connected to mobile data, or - // - We are not connected to mobile data, as long as the *reason* packets are not - // being routed over that link is that we have better connectivity via wifi. - // If data is disconnected for some other reason but wifi (or ethernet/bluetooth) - // is connected, we show nothing. - // Otherwise (nothing connected) we show "No internet connection". - - if (mDataConnected) { - mobileLabel = mNetworkName; - } else if (mConnected || emergencyOnly) { - if (hasService() || emergencyOnly) { - // The isEmergencyOnly test covers the case of a phone with no SIM - mobileLabel = mNetworkName; - } else { - // Tablets, basically - mobileLabel = ""; - } - } else { - mobileLabel - = context.getString(R.string.status_bar_settings_signal_meter_disconnected); - } - - // Now for things that should only be shown when actually using mobile data. - if (mDataConnected) { - combinedSignalIconId = mDataSignalIconId; - - combinedLabel = mobileLabel; - combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon() - mContentDescriptionCombinedSignal = mContentDescriptionDataType; - } - } - - if (mWifiConnected) { - if (mWifiSsid == null) { - wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid); - } else { - wifiLabel = mWifiSsid; - if (DEBUG) { - wifiLabel += "xxxxXXXXxxxxXXXX"; - } - } - - combinedLabel = wifiLabel; - combinedSignalIconId = mWifiIconId; // set by updateWifiIcons() - mContentDescriptionCombinedSignal = mContentDescriptionWifi; - } else { - if (mHasMobileDataFeature) { - wifiLabel = ""; - } else { - wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); - } - } - - if (mBluetoothTethered) { - combinedLabel = mContext.getString(R.string.bluetooth_tethered); - combinedSignalIconId = mBluetoothTetherIconId; - mContentDescriptionCombinedSignal = mContext.getString( - R.string.accessibility_bluetooth_tether); - } - - final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET); - if (ethernetConnected) { - combinedLabel = context.getString(R.string.ethernet_label); - } - - if (mAirplaneMode && - (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { - // Only display the flight-mode icon if not in "emergency calls only" mode. - - // look again; your radios are now airplanes - mContentDescriptionPhoneSignal = mContext.getString( - R.string.accessibility_airplane_mode); - mAirplaneIconId = FLIGHT_MODE_ICON; - mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0; - mQSPhoneSignalIconId = 0; - - // combined values from connected wifi take precedence over airplane mode - if (mWifiConnected) { - // Suppress "No internet connection." from mobile if wifi connected. - mobileLabel = ""; - } else { - if (mHasMobileDataFeature) { - // let the mobile icon show "No internet connection." - wifiLabel = ""; - } else { - wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); - combinedLabel = wifiLabel; - } - mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal; - combinedSignalIconId = mDataSignalIconId; - } - } - else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) { - // pretty much totally disconnected - - combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); - // On devices without mobile radios, we want to show the wifi icon - combinedSignalIconId = - mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId; - mContentDescriptionCombinedSignal = mHasMobileDataFeature - ? mContentDescriptionDataType : mContentDescriptionWifi; - - mDataTypeIconId = 0; - mQSDataTypeIconId = 0; - if (isCdma()) { - if (isCdmaEri()) { - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; - } - } else if (mPhone.isNetworkRoaming()) { - mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; - mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; - } - } - - if (DEBUG) { - Log.d(TAG, "refreshViews connected={" - + (mWifiConnected?" wifi":"") - + (mDataConnected?" data":"") - + " } level=" - + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel())) - + " combinedSignalIconId=0x" - + Integer.toHexString(combinedSignalIconId) - + "/" + getResourceName(combinedSignalIconId) - + " mobileLabel=" + mobileLabel - + " wifiLabel=" + wifiLabel - + " emergencyOnly=" + emergencyOnly - + " combinedLabel=" + combinedLabel - + " mAirplaneMode=" + mAirplaneMode - + " mDataActivity=" + mDataActivity - + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId) - + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId) - + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId) - + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId) - + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId) - + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId) - + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId) - + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId) - + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId)); - } - - // update QS - for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) { - notifySignalsChangedCallbacks(cb); - } - - if (mLastPhoneSignalIconId != mPhoneSignalIconId - || mLastWifiIconId != mWifiIconId - || mLastInetCondition != mInetCondition - || mLastWimaxIconId != mWimaxIconId - || mLastDataTypeIconId != mDataTypeIconId - || mLastAirplaneMode != mAirplaneMode - || mLastLocale != mLocale) - { - // NB: the mLast*s will be updated later - for (SignalCluster cluster : mSignalClusters) { - refreshSignalCluster(cluster); - } - } - - if (mLastAirplaneMode != mAirplaneMode) { - mLastAirplaneMode = mAirplaneMode; - } - - if (mLastLocale != mLocale) { - mLastLocale = mLocale; - } - - // the phone icon on phones - if (mLastPhoneSignalIconId != mPhoneSignalIconId) { - mLastPhoneSignalIconId = mPhoneSignalIconId; - } - - // the data icon on phones - if (mLastDataDirectionIconId != mDataDirectionIconId) { - mLastDataDirectionIconId = mDataDirectionIconId; - } - - // the wifi icon on phones - if (mLastWifiIconId != mWifiIconId) { - mLastWifiIconId = mWifiIconId; - } - - if (mLastInetCondition != mInetCondition) { - mLastInetCondition = mInetCondition; - } - - // the wimax icon on phones - if (mLastWimaxIconId != mWimaxIconId) { - mLastWimaxIconId = mWimaxIconId; - } - // the combined data signal icon - if (mLastCombinedSignalIconId != combinedSignalIconId) { - mLastCombinedSignalIconId = combinedSignalIconId; - } - - // the data network type overlay - if (mLastDataTypeIconId != mDataTypeIconId) { - mLastDataTypeIconId = mDataTypeIconId; - } - - // the combinedLabel in the notification panel - if (!mLastCombinedLabel.equals(combinedLabel)) { - mLastCombinedLabel = combinedLabel; - N = mCombinedLabelViews.size(); - for (int i=0; i<N; i++) { - TextView v = mCombinedLabelViews.get(i); - v.setText(combinedLabel); - } - } - - // wifi label - N = mWifiLabelViews.size(); - for (int i=0; i<N; i++) { - TextView v = mWifiLabelViews.get(i); - v.setText(wifiLabel); - if ("".equals(wifiLabel)) { - v.setVisibility(View.GONE); - } else { - v.setVisibility(View.VISIBLE); - } - } - - // mobile label - N = mMobileLabelViews.size(); - for (int i=0; i<N; i++) { - TextView v = mMobileLabelViews.get(i); - v.setText(mobileLabel); - if ("".equals(mobileLabel)) { - v.setVisibility(View.GONE); - } else { - v.setVisibility(View.VISIBLE); - } - } - - // e-call label - N = mEmergencyLabelViews.size(); - for (int i=0; i<N; i++) { - TextView v = mEmergencyLabelViews.get(i); - if (!emergencyOnly) { - v.setVisibility(View.GONE); - } else { - v.setText(mobileLabel); // comes from the telephony stack - v.setVisibility(View.VISIBLE); - } - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("NetworkController state:"); - pw.println(String.format(" %s network type %d (%s)", - mConnected?"CONNECTED":"DISCONNECTED", - mConnectedNetworkType, mConnectedNetworkTypeName)); - pw.println(" - telephony ------"); - pw.print(" hasVoiceCallingFeature()="); - pw.println(hasVoiceCallingFeature()); - pw.print(" hasService()="); - pw.println(hasService()); - pw.print(" mHspaDataDistinguishable="); - pw.println(mHspaDataDistinguishable); - pw.print(" mDataConnected="); - pw.println(mDataConnected); - pw.print(" mSimState="); - pw.println(mSimState); - pw.print(" mPhoneState="); - pw.println(mPhoneState); - pw.print(" mDataState="); - pw.println(mDataState); - pw.print(" mDataActivity="); - pw.println(mDataActivity); - pw.print(" mDataNetType="); - pw.print(mDataNetType); - pw.print("/"); - pw.println(TelephonyManager.getNetworkTypeName(mDataNetType)); - pw.print(" mServiceState="); - pw.println(mServiceState); - pw.print(" mSignalStrength="); - pw.println(mSignalStrength); - pw.print(" mLastSignalLevel="); - pw.println(mLastSignalLevel); - pw.print(" mNetworkName="); - pw.println(mNetworkName); - pw.print(" mNetworkNameDefault="); - pw.println(mNetworkNameDefault); - pw.print(" mNetworkNameSeparator="); - pw.println(mNetworkNameSeparator.replace("\n","\\n")); - pw.print(" mPhoneSignalIconId=0x"); - pw.print(Integer.toHexString(mPhoneSignalIconId)); - pw.print("/"); - pw.print(" mQSPhoneSignalIconId=0x"); - pw.print(Integer.toHexString(mQSPhoneSignalIconId)); - pw.print("/"); - pw.println(getResourceName(mPhoneSignalIconId)); - pw.print(" mDataDirectionIconId="); - pw.print(Integer.toHexString(mDataDirectionIconId)); - pw.print("/"); - pw.println(getResourceName(mDataDirectionIconId)); - pw.print(" mDataSignalIconId="); - pw.print(Integer.toHexString(mDataSignalIconId)); - pw.print("/"); - pw.println(getResourceName(mDataSignalIconId)); - pw.print(" mDataTypeIconId="); - pw.print(Integer.toHexString(mDataTypeIconId)); - pw.print("/"); - pw.println(getResourceName(mDataTypeIconId)); - pw.print(" mQSDataTypeIconId="); - pw.print(Integer.toHexString(mQSDataTypeIconId)); - pw.print("/"); - pw.println(getResourceName(mQSDataTypeIconId)); - - pw.println(" - wifi ------"); - pw.print(" mWifiEnabled="); - pw.println(mWifiEnabled); - pw.print(" mWifiConnected="); - pw.println(mWifiConnected); - pw.print(" mWifiRssi="); - pw.println(mWifiRssi); - pw.print(" mWifiLevel="); - pw.println(mWifiLevel); - pw.print(" mWifiSsid="); - pw.println(mWifiSsid); - pw.println(String.format(" mWifiIconId=0x%08x/%s", - mWifiIconId, getResourceName(mWifiIconId))); - pw.println(String.format(" mQSWifiIconId=0x%08x/%s", - mQSWifiIconId, getResourceName(mQSWifiIconId))); - pw.print(" mWifiActivity="); - pw.println(mWifiActivity); - - if (mWimaxSupported) { - pw.println(" - wimax ------"); - pw.print(" mIsWimaxEnabled="); pw.println(mIsWimaxEnabled); - pw.print(" mWimaxConnected="); pw.println(mWimaxConnected); - pw.print(" mWimaxIdle="); pw.println(mWimaxIdle); - pw.println(String.format(" mWimaxIconId=0x%08x/%s", - mWimaxIconId, getResourceName(mWimaxIconId))); - pw.println(String.format(" mWimaxSignal=%d", mWimaxSignal)); - pw.println(String.format(" mWimaxState=%d", mWimaxState)); - pw.println(String.format(" mWimaxExtraState=%d", mWimaxExtraState)); - } - - pw.println(" - Bluetooth ----"); - pw.print(" mBtReverseTethered="); - pw.println(mBluetoothTethered); - - pw.println(" - connectivity ------"); - pw.print(" mInetCondition="); - pw.println(mInetCondition); - - pw.println(" - icons ------"); - pw.print(" mLastPhoneSignalIconId=0x"); - pw.print(Integer.toHexString(mLastPhoneSignalIconId)); - pw.print("/"); - pw.println(getResourceName(mLastPhoneSignalIconId)); - pw.print(" mLastDataDirectionIconId=0x"); - pw.print(Integer.toHexString(mLastDataDirectionIconId)); - pw.print("/"); - pw.println(getResourceName(mLastDataDirectionIconId)); - pw.print(" mLastWifiIconId=0x"); - pw.print(Integer.toHexString(mLastWifiIconId)); - pw.print("/"); - pw.println(getResourceName(mLastWifiIconId)); - pw.print(" mLastCombinedSignalIconId=0x"); - pw.print(Integer.toHexString(mLastCombinedSignalIconId)); - pw.print("/"); - pw.println(getResourceName(mLastCombinedSignalIconId)); - pw.print(" mLastDataTypeIconId=0x"); - pw.print(Integer.toHexString(mLastDataTypeIconId)); - pw.print("/"); - pw.println(getResourceName(mLastDataTypeIconId)); - pw.print(" mLastCombinedLabel="); - pw.print(mLastCombinedLabel); - pw.println(""); - } - - private String getResourceName(int resId) { - if (resId != 0) { - final Resources res = mContext.getResources(); - try { - return res.getResourceName(resId); - } catch (android.content.res.Resources.NotFoundException ex) { - return "(unknown)"; - } - } else { - return "(null)"; - } - } - - private boolean mDemoMode; - private int mDemoInetCondition; - private int mDemoWifiLevel; - private int mDemoDataTypeIconId; - private int mDemoMobileLevel; - - @Override - public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mDemoMode = true; - mDemoWifiLevel = mWifiLevel; - mDemoInetCondition = mInetCondition; - mDemoDataTypeIconId = mDataTypeIconId; - mDemoMobileLevel = mLastSignalLevel; - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - for (SignalCluster cluster : mSignalClusters) { - refreshSignalCluster(cluster); - } - } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { - String airplane = args.getString("airplane"); - if (airplane != null) { - boolean show = airplane.equals("show"); - for (SignalCluster cluster : mSignalClusters) { - cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON); - } - } - String fully = args.getString("fully"); - if (fully != null) { - mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0; - } - String wifi = args.getString("wifi"); - if (wifi != null) { - boolean show = wifi.equals("show"); - String level = args.getString("level"); - if (level != null) { - mDemoWifiLevel = level.equals("null") ? -1 - : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); - } - int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null - : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel]; - for (SignalCluster cluster : mSignalClusters) { - cluster.setWifiIndicators( - show, - iconId, - mDemoInetCondition == 0, - "Demo"); - } - } - String mobile = args.getString("mobile"); - if (mobile != null) { - boolean show = mobile.equals("show"); - String datatype = args.getString("datatype"); - if (datatype != null) { - mDemoDataTypeIconId = - datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x : - datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g : - datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g : - datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e : - datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g : - datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h : - datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte : - datatype.equals("roam") - ? R.drawable.stat_sys_data_fully_connected_roam : - 0; - } - int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH; - String level = args.getString("level"); - if (level != null) { - mDemoMobileLevel = level.equals("null") ? -1 - : Math.min(Integer.parseInt(level), icons[0].length - 1); - } - int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null : - icons[mDemoInetCondition][mDemoMobileLevel]; - for (SignalCluster cluster : mSignalClusters) { - cluster.setMobileDataIndicators( - show, - iconId, - mDemoInetCondition == 0, - mDemoDataTypeIconId, - "Demo", - "Demo"); - } - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java new file mode 100644 index 0000000..966c0b0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -0,0 +1,1491 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wimax.WimaxManagerConstants; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.provider.Settings; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.cdma.EriInfo; +import com.android.internal.util.AsyncChannel; +import com.android.systemui.DemoMode; +import com.android.systemui.R; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** Platform implementation of the network controller. **/ +public class NetworkControllerImpl extends BroadcastReceiver + implements NetworkController, DemoMode { + // debug + static final String TAG = "StatusBar.NetworkController"; + static final boolean DEBUG = false; + static final boolean CHATTY = false; // additional diagnostics, but not logspew + + private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode; + + // telephony + boolean mHspaDataDistinguishable; + final TelephonyManager mPhone; + boolean mDataConnected; + IccCardConstants.State mSimState = IccCardConstants.State.READY; + int mPhoneState = TelephonyManager.CALL_STATE_IDLE; + int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + int mDataState = TelephonyManager.DATA_DISCONNECTED; + int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; + ServiceState mServiceState; + SignalStrength mSignalStrength; + int[] mDataIconList = TelephonyIcons.DATA_G[0]; + String mNetworkName; + String mNetworkNameDefault; + String mNetworkNameSeparator; + int mPhoneSignalIconId; + int mQSPhoneSignalIconId; + int mDataDirectionIconId; // data + data direction on phones + int mDataSignalIconId; + int mDataTypeIconId; + int mQSDataTypeIconId; + int mAirplaneIconId; + boolean mDataActive; + int mLastSignalLevel; + boolean mShowPhoneRSSIForData = false; + boolean mShowAtLeastThreeGees = false; + boolean mAlwaysShowCdmaRssi = false; + + String mContentDescriptionPhoneSignal; + String mContentDescriptionWifi; + String mContentDescriptionWimax; + String mContentDescriptionCombinedSignal; + String mContentDescriptionDataType; + + // wifi + final WifiManager mWifiManager; + AsyncChannel mWifiChannel; + boolean mWifiEnabled, mWifiConnected; + int mWifiRssi, mWifiLevel; + String mWifiSsid; + int mWifiIconId = 0; + int mQSWifiIconId = 0; + int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE; + + // bluetooth + private boolean mBluetoothTethered = false; + private int mBluetoothTetherIconId = + com.android.internal.R.drawable.stat_sys_tether_bluetooth; + + //wimax + private boolean mWimaxSupported = false; + private boolean mIsWimaxEnabled = false; + private boolean mWimaxConnected = false; + private boolean mWimaxIdle = false; + private int mWimaxIconId = 0; + private int mWimaxSignal = 0; + private int mWimaxState = 0; + private int mWimaxExtraState = 0; + + // data connectivity (regardless of state, can we access the internet?) + // state of inet connection - 0 not connected, 100 connected + private boolean mConnected = false; + private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE; + private String mConnectedNetworkTypeName; + private int mInetCondition = 0; + private int mLastInetCondition = 0; + private static final int INET_CONDITION_THRESHOLD = 50; + + private boolean mAirplaneMode = false; + private boolean mLastAirplaneMode = true; + + private Locale mLocale = null; + private Locale mLastLocale = null; + + // our ui + Context mContext; + ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>(); + ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>(); + ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>(); + ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>(); + ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>(); + ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks = + new ArrayList<NetworkSignalChangedCallback>(); + int mLastPhoneSignalIconId = -1; + int mLastDataDirectionIconId = -1; + int mLastWifiIconId = -1; + int mLastWimaxIconId = -1; + int mLastCombinedSignalIconId = -1; + int mLastDataTypeIconId = -1; + String mLastCombinedLabel = ""; + + private boolean mHasMobileDataFeature; + + boolean mDataAndWifiStacked = false; + + public interface SignalCluster { + void setWifiIndicators(boolean visible, int strengthIcon, boolean problem, + String contentDescription); + void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem, + int typeIcon, String contentDescription, String typeContentDescription); + void setIsAirplaneMode(boolean is, int airplaneIcon); + } + + /** + * Construct this controller object and register for updates. + */ + public NetworkControllerImpl(Context context) { + mContext = context; + final Resources res = context.getResources(); + + ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + + mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData); + mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G); + mAlwaysShowCdmaRssi = res.getBoolean( + com.android.internal.R.bool.config_alwaysUseCdmaRssi); + + // set up the default wifi icon, used when no radios have ever appeared + updateWifiIcons(); + updateWimaxIcons(); + + // telephony + mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); + mPhone.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_SERVICE_STATE + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS + | PhoneStateListener.LISTEN_CALL_STATE + | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE + | PhoneStateListener.LISTEN_DATA_ACTIVITY); + mHspaDataDistinguishable = mContext.getResources().getBoolean( + R.bool.config_hspa_data_distinguishable); + mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator); + mNetworkNameDefault = mContext.getString( + com.android.internal.R.string.lockscreen_carrier_default); + mNetworkName = mNetworkNameDefault; + + // wifi + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + Handler handler = new WifiHandler(); + mWifiChannel = new AsyncChannel(); + Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger(); + if (wifiMessenger != null) { + mWifiChannel.connect(mContext, handler, wifiMessenger); + } + + // broadcasts + IntentFilter filter = new IntentFilter(); + filter.addAction(WifiManager.RSSI_CHANGED_ACTION); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); + mWimaxSupported = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_wimaxEnabled); + if(mWimaxSupported) { + filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION); + filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION); + filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION); + } + context.registerReceiver(this, filter); + + // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it + updateAirplaneMode(); + + mLastLocale = mContext.getResources().getConfiguration().locale; + } + + public boolean hasMobileDataFeature() { + return mHasMobileDataFeature; + } + + public boolean hasVoiceCallingFeature() { + return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; + } + + public boolean isEmergencyOnly() { + return (mServiceState != null && mServiceState.isEmergencyOnly()); + } + + public void addCombinedLabelView(TextView v) { + mCombinedLabelViews.add(v); + } + + public void addMobileLabelView(TextView v) { + mMobileLabelViews.add(v); + } + + public void addWifiLabelView(TextView v) { + mWifiLabelViews.add(v); + } + + public void addEmergencyLabelView(TextView v) { + mEmergencyLabelViews.add(v); + } + + public void addSignalCluster(SignalCluster cluster) { + mSignalClusters.add(cluster); + refreshSignalCluster(cluster); + } + + public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) { + mSignalsChangedCallbacks.add(cb); + notifySignalsChangedCallbacks(cb); + } + + public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) { + mSignalsChangedCallbacks.remove(cb); + } + + @Override + public void setWifiEnabled(final boolean enabled) { + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... args) { + // Disable tethering if enabling Wifi + final int wifiApState = mWifiManager.getWifiApState(); + if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || + (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { + mWifiManager.setWifiApEnabled(null, false); + } + + mWifiManager.setWifiEnabled(enabled); + return null; + } + }.execute(); + } + + public void refreshSignalCluster(SignalCluster cluster) { + if (mDemoMode) return; + cluster.setWifiIndicators( + // only show wifi in the cluster if connected or if wifi-only + mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature), + mWifiIconId, + mInetCondition == 0, + mContentDescriptionWifi); + + if (mIsWimaxEnabled && mWimaxConnected) { + // wimax is special + cluster.setMobileDataIndicators( + true, + mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId, + mInetCondition == 0, + mDataTypeIconId, + mContentDescriptionWimax, + mContentDescriptionDataType); + } else { + // normal mobile data + cluster.setMobileDataIndicators( + mHasMobileDataFeature, + mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId, + mInetCondition == 0, + mDataTypeIconId, + mContentDescriptionPhoneSignal, + mContentDescriptionDataType); + } + cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId); + } + + void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) { + // only show wifi in the cluster if connected or if wifi-only + boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature); + String wifiDesc = wifiEnabled ? + mWifiSsid : null; + boolean wifiIn = wifiEnabled && mWifiSsid != null + && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT + || mWifiActivity == WifiManager.DATA_ACTIVITY_IN); + boolean wifiOut = wifiEnabled && mWifiSsid != null + && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT + || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT); + cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut, + mContentDescriptionWifi, wifiDesc); + + boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT + || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN); + boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT + || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT); + if (isEmergencyOnly()) { + cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId, + mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, + mContentDescriptionDataType, null); + } else { + if (mIsWimaxEnabled && mWimaxConnected) { + // Wimax is special + cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId, + mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, + mContentDescriptionDataType, mNetworkName); + } else { + // Normal mobile data + cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId, + mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut, + mContentDescriptionDataType, mNetworkName); + } + } + cb.onAirplaneModeChanged(mAirplaneMode); + } + + public void setStackedMode(boolean stacked) { + mDataAndWifiStacked = true; + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.RSSI_CHANGED_ACTION) + || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) + || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + updateWifiState(intent); + refreshViews(); + } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { + updateSimState(intent); + updateDataIcon(); + refreshViews(); + } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { + updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), + intent.getStringExtra(TelephonyIntents.EXTRA_SPN), + intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), + intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); + refreshViews(); + } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || + action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { + updateConnectivity(intent); + refreshViews(); + } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { + refreshLocale(); + refreshViews(); + } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { + refreshLocale(); + updateAirplaneMode(); + refreshViews(); + } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) || + action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) || + action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { + updateWimaxState(intent); + refreshViews(); + } + } + + + // ===== Telephony ============================================================== + + PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + if (DEBUG) { + Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + + ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); + } + mSignalStrength = signalStrength; + updateTelephonySignalStrength(); + refreshViews(); + } + + @Override + public void onServiceStateChanged(ServiceState state) { + if (DEBUG) { + Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState() + + " dataState=" + state.getDataRegState()); + } + mServiceState = state; + updateTelephonySignalStrength(); + updateDataNetType(); + updateDataIcon(); + refreshViews(); + } + + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (DEBUG) { + Log.d(TAG, "onCallStateChanged state=" + state); + } + // In cdma, if a voice call is made, RSSI should switch to 1x. + if (isCdma()) { + updateTelephonySignalStrength(); + refreshViews(); + } + } + + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + if (DEBUG) { + Log.d(TAG, "onDataConnectionStateChanged: state=" + state + + " type=" + networkType); + } + mDataState = state; + mDataNetType = networkType; + updateDataNetType(); + updateDataIcon(); + refreshViews(); + } + + @Override + public void onDataActivity(int direction) { + if (DEBUG) { + Log.d(TAG, "onDataActivity: direction=" + direction); + } + mDataActivity = direction; + updateDataIcon(); + refreshViews(); + } + }; + + private final void updateSimState(Intent intent) { + String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); + if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { + mSimState = IccCardConstants.State.ABSENT; + } + else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { + mSimState = IccCardConstants.State.READY; + } + else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { + final String lockedReason = + intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); + if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { + mSimState = IccCardConstants.State.PIN_REQUIRED; + } + else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { + mSimState = IccCardConstants.State.PUK_REQUIRED; + } + else { + mSimState = IccCardConstants.State.NETWORK_LOCKED; + } + } else { + mSimState = IccCardConstants.State.UNKNOWN; + } + } + + private boolean isCdma() { + return (mSignalStrength != null) && !mSignalStrength.isGsm(); + } + + private boolean hasService() { + if (mServiceState != null) { + // Consider the device to be in service if either voice or data service is available. + // Some SIM cards are marketed as data-only and do not support voice service, and on + // these SIM cards, we want to show signal bars for data service as well as the "no + // service" or "emergency calls only" text that indicates that voice is not available. + switch(mServiceState.getVoiceRegState()) { + case ServiceState.STATE_POWER_OFF: + return false; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; + default: + return true; + } + } else { + return false; + } + } + + private void updateAirplaneMode() { + mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) == 1); + } + + private void refreshLocale() { + mLocale = mContext.getResources().getConfiguration().locale; + } + + private final void updateTelephonySignalStrength() { + if (!hasService()) { + if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()"); + mPhoneSignalIconId = R.drawable.stat_sys_signal_null; + mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; + mDataSignalIconId = R.drawable.stat_sys_signal_null; + } else { + if (mSignalStrength == null) { + if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null"); + mPhoneSignalIconId = R.drawable.stat_sys_signal_null; + mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal; + mDataSignalIconId = R.drawable.stat_sys_signal_null; + mContentDescriptionPhoneSignal = mContext.getString( + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]); + } else { + int iconLevel; + int[] iconList; + if (isCdma() && mAlwaysShowCdmaRssi) { + mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel(); + if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi + + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel() + + " instead of level=" + mSignalStrength.getLevel()); + } else { + mLastSignalLevel = iconLevel = mSignalStrength.getLevel(); + } + + if (isCdma()) { + if (isCdmaEri()) { + iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; + } else { + iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; + } + } else { + // Though mPhone is a Manager, this call is not an IPC + if (mPhone.isNetworkRoaming()) { + iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; + } else { + iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition]; + } + } + mPhoneSignalIconId = iconList[iconLevel]; + mQSPhoneSignalIconId = + TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel]; + mContentDescriptionPhoneSignal = mContext.getString( + AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]); + mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; + } + } + } + + private final void updateDataNetType() { + if (mIsWimaxEnabled && mWimaxConnected) { + // wimax is a special 4g network not handled by telephony + mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_4g); + } else { + switch (mDataNetType) { + case TelephonyManager.NETWORK_TYPE_UNKNOWN: + if (!mShowAtLeastThreeGees) { + mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; + mDataTypeIconId = 0; + mQSDataTypeIconId = 0; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_gprs); + break; + } else { + // fall through + } + case TelephonyManager.NETWORK_TYPE_EDGE: + if (!mShowAtLeastThreeGees) { + mDataIconList = TelephonyIcons.DATA_E[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_edge); + break; + } else { + // fall through + } + case TelephonyManager.NETWORK_TYPE_UMTS: + mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); + break; + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSPAP: + if (mHspaDataDistinguishable) { + mDataIconList = TelephonyIcons.DATA_H[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3_5g); + } else { + mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); + } + break; + case TelephonyManager.NETWORK_TYPE_CDMA: + if (!mShowAtLeastThreeGees) { + // display 1xRTT for IS95A/B + mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_cdma); + break; + } else { + // fall through + } + case TelephonyManager.NETWORK_TYPE_1xRTT: + if (!mShowAtLeastThreeGees) { + mDataIconList = TelephonyIcons.DATA_1X[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_cdma); + break; + } else { + // fall through + } + case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_EHRPD: + mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); + break; + case TelephonyManager.NETWORK_TYPE_LTE: + boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE); + if (show4GforLTE) { + mDataIconList = TelephonyIcons.DATA_4G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_4g); + } else { + mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_lte); + } + break; + default: + if (!mShowAtLeastThreeGees) { + mDataIconList = TelephonyIcons.DATA_G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_gprs); + } else { + mDataIconList = TelephonyIcons.DATA_3G[mInetCondition]; + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition]; + mContentDescriptionDataType = mContext.getString( + R.string.accessibility_data_connection_3g); + } + break; + } + } + + if (isCdma()) { + if (isCdmaEri()) { + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; + } + } else if (mPhone.isNetworkRoaming()) { + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; + } + } + + boolean isCdmaEri() { + if (mServiceState != null) { + final int iconIndex = mServiceState.getCdmaEriIconIndex(); + if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { + final int iconMode = mServiceState.getCdmaEriIconMode(); + if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL + || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { + return true; + } + } + } + return false; + } + + private final void updateDataIcon() { + int iconId; + boolean visible = true; + + if (!isCdma()) { + // GSM case, we have to check also the sim state + if (mSimState == IccCardConstants.State.READY || + mSimState == IccCardConstants.State.UNKNOWN) { + if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { + switch (mDataActivity) { + case TelephonyManager.DATA_ACTIVITY_IN: + iconId = mDataIconList[1]; + break; + case TelephonyManager.DATA_ACTIVITY_OUT: + iconId = mDataIconList[2]; + break; + case TelephonyManager.DATA_ACTIVITY_INOUT: + iconId = mDataIconList[3]; + break; + default: + iconId = mDataIconList[0]; + break; + } + mDataDirectionIconId = iconId; + } else { + iconId = 0; + visible = false; + } + } else { + iconId = R.drawable.stat_sys_no_sim; + visible = false; // no SIM? no data + } + } else { + // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT + if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) { + switch (mDataActivity) { + case TelephonyManager.DATA_ACTIVITY_IN: + iconId = mDataIconList[1]; + break; + case TelephonyManager.DATA_ACTIVITY_OUT: + iconId = mDataIconList[2]; + break; + case TelephonyManager.DATA_ACTIVITY_INOUT: + iconId = mDataIconList[3]; + break; + case TelephonyManager.DATA_ACTIVITY_DORMANT: + default: + iconId = mDataIconList[0]; + break; + } + } else { + iconId = 0; + visible = false; + } + } + + mDataDirectionIconId = iconId; + mDataConnected = visible; + } + + void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { + if (false) { + Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn + + " showPlmn=" + showPlmn + " plmn=" + plmn); + } + StringBuilder str = new StringBuilder(); + boolean something = false; + if (showPlmn && plmn != null) { + str.append(plmn); + something = true; + } + if (showSpn && spn != null) { + if (something) { + str.append(mNetworkNameSeparator); + } + str.append(spn); + something = true; + } + if (something) { + mNetworkName = str.toString(); + } else { + mNetworkName = mNetworkNameDefault; + } + } + + // ===== Wifi =================================================================== + + class WifiHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + mWifiChannel.sendMessage(Message.obtain(this, + AsyncChannel.CMD_CHANNEL_FULL_CONNECTION)); + } else { + Log.e(TAG, "Failed to connect to wifi"); + } + break; + case WifiManager.DATA_ACTIVITY_NOTIFICATION: + if (msg.arg1 != mWifiActivity) { + mWifiActivity = msg.arg1; + refreshViews(); + } + break; + default: + //Ignore + break; + } + } + } + + private void updateWifiState(Intent intent) { + final String action = intent.getAction(); + if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; + + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + final NetworkInfo networkInfo = (NetworkInfo) + intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + boolean wasConnected = mWifiConnected; + mWifiConnected = networkInfo != null && networkInfo.isConnected(); + // If we just connected, grab the inintial signal strength and ssid + if (mWifiConnected && !wasConnected) { + // try getting it out of the intent first + WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); + if (info == null) { + info = mWifiManager.getConnectionInfo(); + } + if (info != null) { + mWifiSsid = huntForSsid(info); + } else { + mWifiSsid = null; + } + } else if (!mWifiConnected) { + mWifiSsid = null; + } + } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { + mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); + mWifiLevel = WifiManager.calculateSignalLevel( + mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT); + } + + updateWifiIcons(); + } + + private void updateWifiIcons() { + if (mWifiConnected) { + mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; + mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel]; + mContentDescriptionWifi = mContext.getString( + AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]); + } else { + if (mDataAndWifiStacked) { + mWifiIconId = 0; + mQSWifiIconId = 0; + } else { + mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0; + mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0; + } + mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi); + } + } + + private String huntForSsid(WifiInfo info) { + String ssid = info.getSSID(); + if (ssid != null) { + return ssid; + } + // OK, it's not in the connectionInfo; we have to go hunting for it + List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks(); + for (WifiConfiguration net : networks) { + if (net.networkId == info.getNetworkId()) { + return net.SSID; + } + } + return null; + } + + + // ===== Wimax =================================================================== + private final void updateWimaxState(Intent intent) { + final String action = intent.getAction(); + boolean wasConnected = mWimaxConnected; + if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) { + int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE, + WimaxManagerConstants.NET_4G_STATE_UNKNOWN); + mIsWimaxEnabled = (wimaxStatus == + WimaxManagerConstants.NET_4G_STATE_ENABLED); + } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) { + mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0); + } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { + mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE, + WimaxManagerConstants.NET_4G_STATE_UNKNOWN); + mWimaxExtraState = intent.getIntExtra( + WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL, + WimaxManagerConstants.NET_4G_STATE_UNKNOWN); + mWimaxConnected = (mWimaxState == + WimaxManagerConstants.WIMAX_STATE_CONNECTED); + mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE); + } + updateDataNetType(); + updateWimaxIcons(); + } + + private void updateWimaxIcons() { + if (mIsWimaxEnabled) { + if (mWimaxConnected) { + if (mWimaxIdle) + mWimaxIconId = WimaxIcons.WIMAX_IDLE; + else + mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal]; + mContentDescriptionWimax = mContext.getString( + AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]); + } else { + mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED; + mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax); + } + } else { + mWimaxIconId = 0; + } + } + + // ===== Full or limited Internet connectivity ================================== + + private void updateConnectivity(Intent intent) { + if (CHATTY) { + Log.d(TAG, "updateConnectivity: intent=" + intent); + } + + final ConnectivityManager connManager = (ConnectivityManager) mContext + .getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkInfo info = connManager.getActiveNetworkInfo(); + + // Are we connected at all, by any interface? + mConnected = info != null && info.isConnected(); + if (mConnected) { + mConnectedNetworkType = info.getType(); + mConnectedNetworkTypeName = info.getTypeName(); + } else { + mConnectedNetworkType = ConnectivityManager.TYPE_NONE; + mConnectedNetworkTypeName = null; + } + + int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); + + if (CHATTY) { + Log.d(TAG, "updateConnectivity: networkInfo=" + info); + Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus); + } + + mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); + + if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) { + mBluetoothTethered = info.isConnected(); + } else { + mBluetoothTethered = false; + } + + // We want to update all the icons, all at once, for any condition change + updateDataNetType(); + updateWimaxIcons(); + updateDataIcon(); + updateTelephonySignalStrength(); + updateWifiIcons(); + } + + + // ===== Update the views ======================================================= + + void refreshViews() { + Context context = mContext; + + int combinedSignalIconId = 0; + String combinedLabel = ""; + String wifiLabel = ""; + String mobileLabel = ""; + int N; + final boolean emergencyOnly = isEmergencyOnly(); + + if (!mHasMobileDataFeature) { + mDataSignalIconId = mPhoneSignalIconId = 0; + mQSPhoneSignalIconId = 0; + mobileLabel = ""; + } else { + // We want to show the carrier name if in service and either: + // - We are connected to mobile data, or + // - We are not connected to mobile data, as long as the *reason* packets are not + // being routed over that link is that we have better connectivity via wifi. + // If data is disconnected for some other reason but wifi (or ethernet/bluetooth) + // is connected, we show nothing. + // Otherwise (nothing connected) we show "No internet connection". + + if (mDataConnected) { + mobileLabel = mNetworkName; + } else if (mConnected || emergencyOnly) { + if (hasService() || emergencyOnly) { + // The isEmergencyOnly test covers the case of a phone with no SIM + mobileLabel = mNetworkName; + } else { + // Tablets, basically + mobileLabel = ""; + } + } else { + mobileLabel + = context.getString(R.string.status_bar_settings_signal_meter_disconnected); + } + + // Now for things that should only be shown when actually using mobile data. + if (mDataConnected) { + combinedSignalIconId = mDataSignalIconId; + + combinedLabel = mobileLabel; + combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon() + mContentDescriptionCombinedSignal = mContentDescriptionDataType; + } + } + + if (mWifiConnected) { + if (mWifiSsid == null) { + wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid); + } else { + wifiLabel = mWifiSsid; + if (DEBUG) { + wifiLabel += "xxxxXXXXxxxxXXXX"; + } + } + + combinedLabel = wifiLabel; + combinedSignalIconId = mWifiIconId; // set by updateWifiIcons() + mContentDescriptionCombinedSignal = mContentDescriptionWifi; + } else { + if (mHasMobileDataFeature) { + wifiLabel = ""; + } else { + wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); + } + } + + if (mBluetoothTethered) { + combinedLabel = mContext.getString(R.string.bluetooth_tethered); + combinedSignalIconId = mBluetoothTetherIconId; + mContentDescriptionCombinedSignal = mContext.getString( + R.string.accessibility_bluetooth_tether); + } + + final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET); + if (ethernetConnected) { + combinedLabel = context.getString(R.string.ethernet_label); + } + + if (mAirplaneMode && + (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { + // Only display the flight-mode icon if not in "emergency calls only" mode. + + // look again; your radios are now airplanes + mContentDescriptionPhoneSignal = mContext.getString( + R.string.accessibility_airplane_mode); + mAirplaneIconId = FLIGHT_MODE_ICON; + mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0; + mQSPhoneSignalIconId = 0; + + // combined values from connected wifi take precedence over airplane mode + if (mWifiConnected) { + // Suppress "No internet connection." from mobile if wifi connected. + mobileLabel = ""; + } else { + if (mHasMobileDataFeature) { + // let the mobile icon show "No internet connection." + wifiLabel = ""; + } else { + wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); + combinedLabel = wifiLabel; + } + mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal; + combinedSignalIconId = mDataSignalIconId; + } + } + else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) { + // pretty much totally disconnected + + combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); + // On devices without mobile radios, we want to show the wifi icon + combinedSignalIconId = + mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId; + mContentDescriptionCombinedSignal = mHasMobileDataFeature + ? mContentDescriptionDataType : mContentDescriptionWifi; + + mDataTypeIconId = 0; + mQSDataTypeIconId = 0; + if (isCdma()) { + if (isCdmaEri()) { + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; + } + } else if (mPhone.isNetworkRoaming()) { + mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam; + mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition]; + } + } + + if (DEBUG) { + Log.d(TAG, "refreshViews connected={" + + (mWifiConnected?" wifi":"") + + (mDataConnected?" data":"") + + " } level=" + + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel())) + + " combinedSignalIconId=0x" + + Integer.toHexString(combinedSignalIconId) + + "/" + getResourceName(combinedSignalIconId) + + " mobileLabel=" + mobileLabel + + " wifiLabel=" + wifiLabel + + " emergencyOnly=" + emergencyOnly + + " combinedLabel=" + combinedLabel + + " mAirplaneMode=" + mAirplaneMode + + " mDataActivity=" + mDataActivity + + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId) + + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId) + + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId) + + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId) + + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId) + + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId) + + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId) + + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId) + + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId)); + } + + // update QS + for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) { + notifySignalsChangedCallbacks(cb); + } + + if (mLastPhoneSignalIconId != mPhoneSignalIconId + || mLastWifiIconId != mWifiIconId + || mLastInetCondition != mInetCondition + || mLastWimaxIconId != mWimaxIconId + || mLastDataTypeIconId != mDataTypeIconId + || mLastAirplaneMode != mAirplaneMode + || mLastLocale != mLocale) + { + // NB: the mLast*s will be updated later + for (SignalCluster cluster : mSignalClusters) { + refreshSignalCluster(cluster); + } + } + + if (mLastAirplaneMode != mAirplaneMode) { + mLastAirplaneMode = mAirplaneMode; + } + + if (mLastLocale != mLocale) { + mLastLocale = mLocale; + } + + // the phone icon on phones + if (mLastPhoneSignalIconId != mPhoneSignalIconId) { + mLastPhoneSignalIconId = mPhoneSignalIconId; + } + + // the data icon on phones + if (mLastDataDirectionIconId != mDataDirectionIconId) { + mLastDataDirectionIconId = mDataDirectionIconId; + } + + // the wifi icon on phones + if (mLastWifiIconId != mWifiIconId) { + mLastWifiIconId = mWifiIconId; + } + + if (mLastInetCondition != mInetCondition) { + mLastInetCondition = mInetCondition; + } + + // the wimax icon on phones + if (mLastWimaxIconId != mWimaxIconId) { + mLastWimaxIconId = mWimaxIconId; + } + // the combined data signal icon + if (mLastCombinedSignalIconId != combinedSignalIconId) { + mLastCombinedSignalIconId = combinedSignalIconId; + } + + // the data network type overlay + if (mLastDataTypeIconId != mDataTypeIconId) { + mLastDataTypeIconId = mDataTypeIconId; + } + + // the combinedLabel in the notification panel + if (!mLastCombinedLabel.equals(combinedLabel)) { + mLastCombinedLabel = combinedLabel; + N = mCombinedLabelViews.size(); + for (int i=0; i<N; i++) { + TextView v = mCombinedLabelViews.get(i); + v.setText(combinedLabel); + } + } + + // wifi label + N = mWifiLabelViews.size(); + for (int i=0; i<N; i++) { + TextView v = mWifiLabelViews.get(i); + v.setText(wifiLabel); + if ("".equals(wifiLabel)) { + v.setVisibility(View.GONE); + } else { + v.setVisibility(View.VISIBLE); + } + } + + // mobile label + N = mMobileLabelViews.size(); + for (int i=0; i<N; i++) { + TextView v = mMobileLabelViews.get(i); + v.setText(mobileLabel); + if ("".equals(mobileLabel)) { + v.setVisibility(View.GONE); + } else { + v.setVisibility(View.VISIBLE); + } + } + + // e-call label + N = mEmergencyLabelViews.size(); + for (int i=0; i<N; i++) { + TextView v = mEmergencyLabelViews.get(i); + if (!emergencyOnly) { + v.setVisibility(View.GONE); + } else { + v.setText(mobileLabel); // comes from the telephony stack + v.setVisibility(View.VISIBLE); + } + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("NetworkController state:"); + pw.println(String.format(" %s network type %d (%s)", + mConnected?"CONNECTED":"DISCONNECTED", + mConnectedNetworkType, mConnectedNetworkTypeName)); + pw.println(" - telephony ------"); + pw.print(" hasVoiceCallingFeature()="); + pw.println(hasVoiceCallingFeature()); + pw.print(" hasService()="); + pw.println(hasService()); + pw.print(" mHspaDataDistinguishable="); + pw.println(mHspaDataDistinguishable); + pw.print(" mDataConnected="); + pw.println(mDataConnected); + pw.print(" mSimState="); + pw.println(mSimState); + pw.print(" mPhoneState="); + pw.println(mPhoneState); + pw.print(" mDataState="); + pw.println(mDataState); + pw.print(" mDataActivity="); + pw.println(mDataActivity); + pw.print(" mDataNetType="); + pw.print(mDataNetType); + pw.print("/"); + pw.println(TelephonyManager.getNetworkTypeName(mDataNetType)); + pw.print(" mServiceState="); + pw.println(mServiceState); + pw.print(" mSignalStrength="); + pw.println(mSignalStrength); + pw.print(" mLastSignalLevel="); + pw.println(mLastSignalLevel); + pw.print(" mNetworkName="); + pw.println(mNetworkName); + pw.print(" mNetworkNameDefault="); + pw.println(mNetworkNameDefault); + pw.print(" mNetworkNameSeparator="); + pw.println(mNetworkNameSeparator.replace("\n","\\n")); + pw.print(" mPhoneSignalIconId=0x"); + pw.print(Integer.toHexString(mPhoneSignalIconId)); + pw.print("/"); + pw.print(" mQSPhoneSignalIconId=0x"); + pw.print(Integer.toHexString(mQSPhoneSignalIconId)); + pw.print("/"); + pw.println(getResourceName(mPhoneSignalIconId)); + pw.print(" mDataDirectionIconId="); + pw.print(Integer.toHexString(mDataDirectionIconId)); + pw.print("/"); + pw.println(getResourceName(mDataDirectionIconId)); + pw.print(" mDataSignalIconId="); + pw.print(Integer.toHexString(mDataSignalIconId)); + pw.print("/"); + pw.println(getResourceName(mDataSignalIconId)); + pw.print(" mDataTypeIconId="); + pw.print(Integer.toHexString(mDataTypeIconId)); + pw.print("/"); + pw.println(getResourceName(mDataTypeIconId)); + pw.print(" mQSDataTypeIconId="); + pw.print(Integer.toHexString(mQSDataTypeIconId)); + pw.print("/"); + pw.println(getResourceName(mQSDataTypeIconId)); + + pw.println(" - wifi ------"); + pw.print(" mWifiEnabled="); + pw.println(mWifiEnabled); + pw.print(" mWifiConnected="); + pw.println(mWifiConnected); + pw.print(" mWifiRssi="); + pw.println(mWifiRssi); + pw.print(" mWifiLevel="); + pw.println(mWifiLevel); + pw.print(" mWifiSsid="); + pw.println(mWifiSsid); + pw.println(String.format(" mWifiIconId=0x%08x/%s", + mWifiIconId, getResourceName(mWifiIconId))); + pw.println(String.format(" mQSWifiIconId=0x%08x/%s", + mQSWifiIconId, getResourceName(mQSWifiIconId))); + pw.print(" mWifiActivity="); + pw.println(mWifiActivity); + + if (mWimaxSupported) { + pw.println(" - wimax ------"); + pw.print(" mIsWimaxEnabled="); pw.println(mIsWimaxEnabled); + pw.print(" mWimaxConnected="); pw.println(mWimaxConnected); + pw.print(" mWimaxIdle="); pw.println(mWimaxIdle); + pw.println(String.format(" mWimaxIconId=0x%08x/%s", + mWimaxIconId, getResourceName(mWimaxIconId))); + pw.println(String.format(" mWimaxSignal=%d", mWimaxSignal)); + pw.println(String.format(" mWimaxState=%d", mWimaxState)); + pw.println(String.format(" mWimaxExtraState=%d", mWimaxExtraState)); + } + + pw.println(" - Bluetooth ----"); + pw.print(" mBtReverseTethered="); + pw.println(mBluetoothTethered); + + pw.println(" - connectivity ------"); + pw.print(" mInetCondition="); + pw.println(mInetCondition); + + pw.println(" - icons ------"); + pw.print(" mLastPhoneSignalIconId=0x"); + pw.print(Integer.toHexString(mLastPhoneSignalIconId)); + pw.print("/"); + pw.println(getResourceName(mLastPhoneSignalIconId)); + pw.print(" mLastDataDirectionIconId=0x"); + pw.print(Integer.toHexString(mLastDataDirectionIconId)); + pw.print("/"); + pw.println(getResourceName(mLastDataDirectionIconId)); + pw.print(" mLastWifiIconId=0x"); + pw.print(Integer.toHexString(mLastWifiIconId)); + pw.print("/"); + pw.println(getResourceName(mLastWifiIconId)); + pw.print(" mLastCombinedSignalIconId=0x"); + pw.print(Integer.toHexString(mLastCombinedSignalIconId)); + pw.print("/"); + pw.println(getResourceName(mLastCombinedSignalIconId)); + pw.print(" mLastDataTypeIconId=0x"); + pw.print(Integer.toHexString(mLastDataTypeIconId)); + pw.print("/"); + pw.println(getResourceName(mLastDataTypeIconId)); + pw.print(" mLastCombinedLabel="); + pw.print(mLastCombinedLabel); + pw.println(""); + } + + private String getResourceName(int resId) { + if (resId != 0) { + final Resources res = mContext.getResources(); + try { + return res.getResourceName(resId); + } catch (android.content.res.Resources.NotFoundException ex) { + return "(unknown)"; + } + } else { + return "(null)"; + } + } + + private boolean mDemoMode; + private int mDemoInetCondition; + private int mDemoWifiLevel; + private int mDemoDataTypeIconId; + private int mDemoMobileLevel; + + @Override + public void dispatchDemoCommand(String command, Bundle args) { + if (!mDemoMode && command.equals(COMMAND_ENTER)) { + mDemoMode = true; + mDemoWifiLevel = mWifiLevel; + mDemoInetCondition = mInetCondition; + mDemoDataTypeIconId = mDataTypeIconId; + mDemoMobileLevel = mLastSignalLevel; + } else if (mDemoMode && command.equals(COMMAND_EXIT)) { + mDemoMode = false; + for (SignalCluster cluster : mSignalClusters) { + refreshSignalCluster(cluster); + } + } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { + String airplane = args.getString("airplane"); + if (airplane != null) { + boolean show = airplane.equals("show"); + for (SignalCluster cluster : mSignalClusters) { + cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON); + } + } + String fully = args.getString("fully"); + if (fully != null) { + mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0; + } + String wifi = args.getString("wifi"); + if (wifi != null) { + boolean show = wifi.equals("show"); + String level = args.getString("level"); + if (level != null) { + mDemoWifiLevel = level.equals("null") ? -1 + : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); + } + int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null + : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel]; + for (SignalCluster cluster : mSignalClusters) { + cluster.setWifiIndicators( + show, + iconId, + mDemoInetCondition == 0, + "Demo"); + } + } + String mobile = args.getString("mobile"); + if (mobile != null) { + boolean show = mobile.equals("show"); + String datatype = args.getString("datatype"); + if (datatype != null) { + mDemoDataTypeIconId = + datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x : + datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g : + datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g : + datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e : + datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g : + datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h : + datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte : + datatype.equals("roam") + ? R.drawable.stat_sys_data_fully_connected_roam : + 0; + } + int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH; + String level = args.getString("level"); + if (level != null) { + mDemoMobileLevel = level.equals("null") ? -1 + : Math.min(Integer.parseInt(level), icons[0].length - 1); + } + int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null : + icons[mDemoInetCondition][mDemoMobileLevel]; + for (SignalCluster cluster : mSignalClusters) { + cluster.setMobileDataIndicators( + show, + iconId, + mDemoInetCondition == 0, + mDemoDataTypeIconId, + "Demo", + "Demo"); + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java index 98d205a..1eb678d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,65 +16,15 @@ package com.android.systemui.statusbar.policy; -import android.content.Context; -import android.content.res.Configuration; -import android.os.UserHandle; - -import com.android.internal.view.RotationPolicy; - -import java.util.concurrent.CopyOnWriteArrayList; - -public final class RotationLockController { - private final Context mContext; - private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks = - new CopyOnWriteArrayList<RotationLockControllerCallback>(); - - private final RotationPolicy.RotationPolicyListener mRotationPolicyListener = - new RotationPolicy.RotationPolicyListener() { - @Override - public void onChange() { - notifyChanged(); - } - }; +public interface RotationLockController extends Disposable { + int getRotationLockOrientation(); + boolean isRotationLockAffordanceVisible(); + boolean isRotationLocked(); + void setRotationLocked(boolean locked); + void addRotationLockControllerCallback(RotationLockControllerCallback callback); + void removeRotationLockControllerCallback(RotationLockControllerCallback callback); public interface RotationLockControllerCallback { - public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible); - } - - public RotationLockController(Context context) { - mContext = context; - RotationPolicy.registerRotationPolicyListener(mContext, - mRotationPolicyListener, UserHandle.USER_ALL); - } - - public void addRotationLockControllerCallback(RotationLockControllerCallback callback) { - mCallbacks.add(callback); - } - - public int getRotationLockOrientation() { - return RotationPolicy.getRotationLockOrientation(mContext); - } - - public boolean isRotationLocked() { - return RotationPolicy.isRotationLocked(mContext); - } - - public void setRotationLocked(boolean locked) { - RotationPolicy.setRotationLock(mContext, locked); - } - - public boolean isRotationLockAffordanceVisible() { - return RotationPolicy.isRotationLockToggleVisible(mContext); - } - - public void release() { - RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener); - } - - private void notifyChanged() { - for (RotationLockControllerCallback callback : mCallbacks) { - callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext), - RotationPolicy.isRotationLockToggleVisible(mContext)); - } + void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java new file mode 100644 index 0000000..caa07ef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.content.Context; +import android.os.UserHandle; + +import com.android.internal.view.RotationPolicy; + +import java.util.concurrent.CopyOnWriteArrayList; + +/** Platform implementation of the rotation lock controller. **/ +public final class RotationLockControllerImpl implements RotationLockController { + private final Context mContext; + private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks = + new CopyOnWriteArrayList<RotationLockControllerCallback>(); + + private final RotationPolicy.RotationPolicyListener mRotationPolicyListener = + new RotationPolicy.RotationPolicyListener() { + @Override + public void onChange() { + notifyChanged(); + } + }; + + public RotationLockControllerImpl(Context context) { + mContext = context; + RotationPolicy.registerRotationPolicyListener(mContext, + mRotationPolicyListener, UserHandle.USER_ALL); + } + + public void addRotationLockControllerCallback(RotationLockControllerCallback callback) { + mCallbacks.add(callback); + } + + public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) { + mCallbacks.remove(callback); + } + + public int getRotationLockOrientation() { + return RotationPolicy.getRotationLockOrientation(mContext); + } + + public boolean isRotationLocked() { + return RotationPolicy.isRotationLocked(mContext); + } + + public void setRotationLocked(boolean locked) { + RotationPolicy.setRotationLock(mContext, locked); + } + + public boolean isRotationLockAffordanceVisible() { + return RotationPolicy.isRotationLockToggleVisible(mContext); + } + + @Override + public void dispose() { + RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener); + } + + private void notifyChanged() { + for (RotationLockControllerCallback callback : mCallbacks) { + callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext), + RotationPolicy.isRotationLockToggleVisible(mContext)); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java new file mode 100644 index 0000000..143ebaa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +public interface TetheringController { + void addCallback(Callback callback); + void removeCallback(Callback callback); + boolean isHotspotEnabled(); + boolean isHotspotSupported(); + + public interface Callback { + void onHotspotChanged(boolean hotspot); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java new file mode 100644 index 0000000..6225c12 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.service.notification.Condition; + +public interface ZenModeController { + void addCallback(Callback callback); + void removeCallback(Callback callback); + void setZen(boolean zen); + boolean isZen(); + void requestConditions(boolean request); + void select(Condition condition); + + public static class Callback { + public void onZenChanged(boolean zen) {} + public void onConditionsChanged(Condition[] conditions) {} + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java new file mode 100644 index 0000000..d760f78 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.app.INotificationManager; +import android.content.Context; +import android.net.Uri; +import android.os.Handler; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings.Global; +import android.service.notification.Condition; +import android.service.notification.IConditionListener; +import android.util.Slog; + +import com.android.systemui.qs.GlobalSetting; + +import java.util.ArrayList; +import java.util.LinkedHashMap; + +/** Platform implementation of the zen mode controller. **/ +public class ZenModeControllerImpl implements ZenModeController { + private static final String TAG = "ZenModeControllerImpl"; + + private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); + private final Context mContext; + private final GlobalSetting mSetting; + private final INotificationManager mNoMan; + private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>(); + + private boolean mRequesting; + + public ZenModeControllerImpl(Context context, Handler handler) { + mContext = context; + mSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) { + @Override + protected void handleValueChanged(int value) { + fireZenChanged(value != 0); + } + }; + mNoMan = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + } + + @Override + public void addCallback(Callback callback) { + mCallbacks.add(callback); + } + + @Override + public void removeCallback(Callback callback) { + mCallbacks.remove(callback); + } + + @Override + public boolean isZen() { + return mSetting.getValue() != 0; + } + + @Override + public void setZen(boolean zen) { + mSetting.setValue(zen ? 1 : 0); + } + + @Override + public void requestConditions(boolean request) { + mRequesting = request; + try { + mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0); + } catch (RemoteException e) { + // noop + } + if (!mRequesting) { + mConditions.clear(); + } + } + + @Override + public void select(Condition condition) { + try { + mNoMan.setZenModeCondition(condition == null ? null : condition.id); + } catch (RemoteException e) { + // noop + } + } + + private void fireZenChanged(boolean zen) { + for (Callback cb : mCallbacks) { + cb.onZenChanged(zen); + } + } + + private void fireConditionsChanged(Condition[] conditions) { + for (Callback cb : mCallbacks) { + cb.onConditionsChanged(conditions); + } + } + + private void updateConditions(Condition[] conditions) { + if (conditions == null || conditions.length == 0) return; + for (Condition c : conditions) { + if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue; + mConditions.put(c.id, c); + } + fireConditionsChanged( + mConditions.values().toArray(new Condition[mConditions.values().size()])); + } + + private final IConditionListener mListener = new IConditionListener.Stub() { + @Override + public void onConditionsReceived(Condition[] conditions) { + Slog.d(TAG, "onConditionsReceived " + (conditions == null ? 0 : conditions.length) + + " mRequesting=" + mRequesting); + if (!mRequesting) return; + updateConditions(conditions); + } + }; +} diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index d074565..007032e 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -16,8 +16,13 @@ package com.android.server.notification; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.Uri; import android.os.Handler; import android.os.IBinder; @@ -30,6 +35,7 @@ import android.service.notification.ConditionProviderService; import android.service.notification.IConditionListener; import android.service.notification.IConditionProvider; import android.service.notification.ZenModeConfig; +import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -39,6 +45,7 @@ import com.android.internal.R; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; public class ConditionProviders extends ManagedServices { private static final Condition[] NO_CONDITIONS = new Condition[0]; @@ -47,6 +54,7 @@ public class ConditionProviders extends ManagedServices { private final ArrayMap<IBinder, IConditionListener> mListeners = new ArrayMap<IBinder, IConditionListener>(); private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>(); + private final CountdownConditionHelper mCountdownHelper = new CountdownConditionHelper(); public ConditionProviders(Context context, Handler handler, UserProfiles userProfiles, ZenModeHelper zenModeHelper) { @@ -267,6 +275,7 @@ public class ConditionProviders extends ManagedServices { } } } + mCountdownHelper.setZenModeCondition(conditionId); } private void subscribeLocked(ConditionRecord r) { @@ -434,6 +443,68 @@ public class ConditionProviders extends ManagedServices { mZenModeHelper.setConfig(config); } + private final class CountdownConditionHelper extends BroadcastReceiver { + private static final String ACTION = "CountdownConditionHelper"; + private static final int REQUEST_CODE = 100; + private static final String EXTRA_TIME = "time"; + + private long mCurrent; + + public CountdownConditionHelper() { + mContext.registerReceiver(this, new IntentFilter(ACTION)); + } + + public void setZenModeCondition(Uri conditionId) { + final long time = tryParseCondition(conditionId); + final AlarmManager alarms = (AlarmManager) + mContext.getSystemService(Context.ALARM_SERVICE); + final Intent intent = new Intent(ACTION).putExtra(EXTRA_TIME, time) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE, + intent, PendingIntent.FLAG_UPDATE_CURRENT); + alarms.cancel(pendingIntent); + mCurrent = time; + if (time > 0) { + final long now = System.currentTimeMillis(); + final CharSequence span = + DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); + Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future (%s), now=%s", + ACTION, ts(time), time - now, span, ts(now))); + alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent); + } + } + + private String ts(long time) { + return new Date(time) + " (" + time + ")"; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION.equals(intent.getAction())) { + final long time = intent.getLongExtra(EXTRA_TIME, 0); + Slog.d(TAG, "Countdown condition fired. time=" + time + " mCurrent=" + mCurrent); + if (time > 0 && time == mCurrent) { + // countdown condition is still the manual condition, leave zen + mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF); + ConditionProviders.this.setZenModeCondition(null); + } + } + } + + private long tryParseCondition(Uri conditionId) { + // condition://android/countdown/1399917958951 + if (!Condition.isValidId(conditionId, "android")) return 0; + if (conditionId.getPathSegments().size() != 2 + || !"countdown".equals(conditionId.getPathSegments().get(0))) return 0; + try { + return Long.parseLong(conditionId.getPathSegments().get(1)); + } catch (RuntimeException e) { + Slog.w(TAG, "Error parsing countdown condition: " + conditionId, e); + return 0; + } + } + } + private class ZenModeHelperCallback extends ZenModeHelper.Callback { @Override void onConfigChanged() { diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index d34b09c..584145f 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -66,7 +66,7 @@ abstract public class ManagedServices { private static final String ENABLED_SERVICES_SEPARATOR = ":"; - private final Context mContext; + protected final Context mContext; protected final Object mMutex; private final UserProfiles mUserProfiles; private final SettingsObserver mSettingsObserver; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7a4f951..f1c05ac 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1401,7 +1401,12 @@ public class NotificationManagerService extends SystemService { @Override public void setZenModeCondition(Uri conditionId) { enforceSystemOrSystemUI("INotificationManager.setZenModeCondition"); - mConditionProviders.setZenModeCondition(conditionId); + final long identity = Binder.clearCallingIdentity(); + try { + mConditionProviders.setZenModeCondition(conditionId); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override |