Initial commit

This commit is contained in:
Peter Cai 2023-04-25 13:41:30 -04:00
commit 10a7f2f520
96 changed files with 5445 additions and 0 deletions

13
.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
*.iml
.gradle
/local.properties
.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
*.jks
*.keystore
keystore.properties

111
AndroidManifest.xml Normal file
View file

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015-2016 The CyanogenMod Project
2017-2018 The LineageOS Project
2020-2022 Paranoid Android
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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.typeblog.lunatic"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk
android:minSdkVersion="31"
android:targetSdkVersion="31"/>
<application
android:label="@string/spotlight_settings_app_name"
android:persistent="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
<receiver
android:name="net.typeblog.lunatic.BootCompletedReceiver"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service
android:name="net.typeblog.lunatic.Services.CallReceiverService"
android:permission="android.permission.READ_PHONE_STATE">
</service>
<service
android:name="net.typeblog.lunatic.Services.ChargingService">
</service>
<service
android:name="net.typeblog.lunatic.Services.FlashlightService">
</service>
<service
android:name="net.typeblog.lunatic.Services.MusicService">
</service>
<service
android:name="net.typeblog.lunatic.Services.NotificationService"
android:exported="false"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<activity
android:name="net.typeblog.lunatic.Settings.SettingsActivity"
android:exported="true"
android:label="@string/spotlight_settings_title"
android:theme="@style/Theme.SubSettingsBase">
<!--<intent-filter>
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.homepage" />
<meta-data
android:name="com.android.settings.icon"
android:resource="@drawable/ic_spotlights_logo" />
<meta-data
android:name="com.android.settings.summary"
android:value="@string/spotlight_settings_summary" />
<meta-data
android:name="com.android.settings.order"
android:value="-105" />-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="net.typeblog.lunatic.Settings.NotifsSettingsActivity"
android:exported="false"
android:theme="@style/Theme.SubSettingsBase">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>
</manifest>

1
SettingsLib/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,21 @@
<?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
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib">
<uses-sdk android:minSdkVersion="29" />
</manifest>

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:outlineAmbientShadowColor="@android:color/transparent"
android:outlineSpotShadowColor="@android:color/transparent"
android:background="?android:attr/colorPrimary"
android:theme="@style/Theme.CollapsingToolbar.Settings">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/settingslib_toolbar_layout_height"
android:clipToPadding="false"
app:forceApplySystemWindowInsetTop="true"
app:extraMultilineHeightEnabled="true"
app:contentScrim="@color/settingslib_colorSurfaceHeader"
app:maxLines="3"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:scrimAnimationDuration="50"
app:scrimVisibleHeightTrigger="@dimen/settingslib_scrim_visible_height_trigger"
app:statusBarScrim="@null"
app:titleCollapseMode="fade"
app:collapsedTitleTextAppearance="@style/CollapsingToolbarTitle.Collapsed"
app:expandedTitleTextAppearance="@style/CollapsingToolbarTitle.Expanded"
app:expandedTitleMarginStart="@dimen/expanded_title_margin_start"
app:expandedTitleMarginEnd="@dimen/expanded_title_margin_end"
app:toolbarId="@id/action_bar">
<Toolbar
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="?android:attr/actionBarTheme"
android:transitionName="shared_element_view"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<!-- The main content view -->
<LinearLayout
android:id="@+id/content_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:transitionGroup="true"
android:orientation="vertical">
<Toolbar
android:id="@+id/action_bar"
style="?android:attr/actionBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?android:attr/actionBarTheme" />
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
<item name="colorPrimary">@color/settingslib_primary_dark_device_default_settings</item>
<item name="colorAccent">@color/settingslib_accent_device_default_dark</item>
</style>
</resources>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Collapsing toolbar layout dimensions -->
<dimen name="settingslib_toolbar_layout_height">179dp</dimen>
<dimen name="settingslib_scrim_visible_height_trigger">137dp</dimen>
<dimen name="expanded_title_margin_start">24dp</dimen>
<dimen name="expanded_title_margin_end">24dp</dimen>
</resources>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20dp</item>
<item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
</style>
<style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
<item name="android:textSize">36dp</item>
<item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
</style>
</resources>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
<item name="colorPrimary">@color/settingslib_primary_device_default_settings_light</item>
<item name="colorAccent">@color/settingslib_accent_device_default_light</item>
</style>
</resources>

View file

@ -0,0 +1,172 @@
/*
* Copyright (C) 2021 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.settingslib.collapsingtoolbar;
import android.app.ActionBar;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.resources.TextAppearanceConfig;
import com.android.settingslib.R;
/**
* A base Activity that has a collapsing toolbar layout is used for the activities intending to
* enable the collapsing toolbar function.
*/
public class CollapsingToolbarBaseActivity extends FragmentActivity {
private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
@Nullable
private CollapsingToolbarLayout mCollapsingToolbarLayout;
@Nullable
private AppBarLayout mAppBarLayout;
private int mCustomizeLayoutResId = 0;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mCustomizeLayoutResId > 0 && !true) {
super.setContentView(mCustomizeLayoutResId);
return;
}
// Force loading font synchronously for collapsing toolbar layout
TextAppearanceConfig.setShouldLoadFontSynchronously(true);
super.setContentView(R.layout.collapsing_toolbar_base_layout);
mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
mAppBarLayout = findViewById(R.id.app_bar);
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
}
disableCollapsingToolbarLayoutScrollingBehavior();
final Toolbar toolbar = findViewById(R.id.action_bar);
setActionBar(toolbar);
// Enable title and home button by default
final ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
}
}
@Override
public void setContentView(int layoutResID) {
final ViewGroup parent = findViewById(R.id.content_frame);
if (parent != null) {
parent.removeAllViews();
}
LayoutInflater.from(this).inflate(layoutResID, parent);
}
@Override
public void setContentView(View view) {
final ViewGroup parent = findViewById(R.id.content_frame);
if (parent != null) {
parent.addView(view);
}
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
final ViewGroup parent = findViewById(R.id.content_frame);
if (parent != null) {
parent.addView(view, params);
}
}
/**
* This method allows an activity to replace the default layout with a customize layout. Notice
* that it will no longer apply the features being provided by this class when this method
* gets called.
*/
protected void setCustomizeContentView(int layoutResId) {
mCustomizeLayoutResId = layoutResId;
}
@Override
public void setTitle(CharSequence title) {
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setTitle(title);
} else {
super.setTitle(title);
}
}
@Override
public void setTitle(int titleId) {
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setTitle(getText(titleId));
} else {
super.setTitle(titleId);
}
}
@Override
public boolean onNavigateUp() {
if (!super.onNavigateUp()) {
finishAfterTransition();
}
return true;
}
/**
* Returns an instance of collapsing toolbar.
*/
@Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return mCollapsingToolbarLayout;
}
/**
* Return an instance of app bar.
*/
@Nullable
public AppBarLayout getAppBarLayout() {
return mAppBarLayout;
}
private void disableCollapsingToolbarLayoutScrollingBehavior() {
if (mAppBarLayout == null) {
return;
}
final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
behavior.setDragCallback(
new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
params.setBehavior(behavior);
}
}

View file

@ -0,0 +1,130 @@
/*
* Copyright (C) 2021 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.settingslib.collapsingtoolbar;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.android.settingslib.R;
/**
* A base fragment that has a collapsing toolbar layout for enabling the collapsing toolbar design.
*/
public abstract class CollapsingToolbarBaseFragment extends Fragment {
private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
@Nullable
private CoordinatorLayout mCoordinatorLayout;
@Nullable
private CollapsingToolbarLayout mCollapsingToolbarLayout;
@Nullable
private AppBarLayout mAppBarLayout;
@NonNull
private Toolbar mToolbar;
@NonNull
private FrameLayout mContentFrameLayout;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
mCoordinatorLayout = view.findViewById(R.id.content_parent);
}
mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
mAppBarLayout = view.findViewById(R.id.app_bar);
if (mCollapsingToolbarLayout != null) {
mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
}
disableCollapsingToolbarLayoutScrollingBehavior();
mToolbar = view.findViewById(R.id.action_bar);
mContentFrameLayout = view.findViewById(R.id.content_frame);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
requireActivity().setActionBar(mToolbar);
}
/**
* Return an instance of CoordinatorLayout.
*/
@Nullable
public CoordinatorLayout getCoordinatorLayout() {
return mCoordinatorLayout;
}
/**
* Return an instance of app bar.
*/
@Nullable
public AppBarLayout getAppBarLayout() {
return mAppBarLayout;
}
/**
* Return the collapsing toolbar layout.
*/
@Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return mCollapsingToolbarLayout;
}
/**
* Return the content frame layout.
*/
@NonNull
public FrameLayout getContentFrameLayout() {
return mContentFrameLayout;
}
private void disableCollapsingToolbarLayoutScrollingBehavior() {
if (mAppBarLayout == null) {
return;
}
final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
behavior.setDragCallback(
new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
params.setBehavior(behavior);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2021 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.settingslib.collapsingtoolbar;
import androidx.fragment.app.FragmentActivity;
/**
* A base Activity for Settings-specific page transition. Activities extending it will get
* Settings transition applied.
*/
public abstract class SettingsTransitionActivity extends FragmentActivity {
private static final String TAG = "SettingsTransitionActivity";
protected boolean isSettingsTransitionEnabled() {
return false;
}
}

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_protection_color"/>
<corners android:radius="28dp"/>
<size android:width="@dimen/settingslib_illustration_width"
android:height="@dimen/settingslib_illustration_height"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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_height="wrap_content"
android:layout_width="match_parent"
android:background="?android:attr/colorBackground"
android:importantForAccessibility="noHideDescendants"
android:gravity="center"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/illustration_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:paddingHorizontal="@dimen/settingslib_illustration_padding"
android:orientation="vertical">
<ImageView
android:id="@+id/background_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:src="@drawable/protection_background"/>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxWidth="@dimen/settingslib_illustration_width"
android:maxHeight="@dimen/settingslib_illustration_height"
android:adjustViewBounds="true"/>
<FrameLayout
android:id="@+id/middleground_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>
</FrameLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<color name="settingslib_protection_color">@android:color/black</color>
</resources>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<color name="settingslib_protection_color">@android:color/white</color>
<!-- Dynamic colors-->
<color name="settingslib_color_blue600">#1a73e8</color>
<color name="settingslib_color_blue400">#669df6</color>
<color name="settingslib_color_blue300">#8ab4f8</color>
<color name="settingslib_color_blue100">#d2e3fc</color>
<color name="settingslib_color_blue50">#e8f0fe</color>
<color name="settingslib_color_green600">#1e8e3e</color>
<color name="settingslib_color_green400">#5bb974</color>
<color name="settingslib_color_green100">#ceead6</color>
<color name="settingslib_color_green50">#e6f4ea</color>
<color name="settingslib_color_red600">#d93025</color>
<color name="settingslib_color_red400">#ee675c</color>
<color name="settingslib_color_red100">#fad2cf</color>
<color name="settingslib_color_red50">#fce8e6</color>
<color name="settingslib_color_yellow600">#f9ab00</color>
<color name="settingslib_color_yellow400">#fcc934</color>
<color name="settingslib_color_yellow100">#feefc3</color>
<color name="settingslib_color_yellow50">#fef7e0</color>
<color name="settingslib_color_grey900">#202124</color>
<color name="settingslib_color_grey800">#3c4043</color>
<color name="settingslib_color_grey700">#5f6368</color>
<color name="settingslib_color_grey600">#80868b</color>
<color name="settingslib_color_grey400">#bdc1c6</color>
<color name="settingslib_color_grey300">#dadce0</color>
<color name="settingslib_color_grey200">#e8eaed</color>
<color name="settingslib_color_orange600">#e8710a</color>
<color name="settingslib_color_orange400">#fa903e</color>
<color name="settingslib_color_orange300">#fcad70</color>
<color name="settingslib_color_orange100">#fedfc8</color>
<color name="settingslib_color_pink600">#e52592</color>
<color name="settingslib_color_pink400">#ff63b8</color>
<color name="settingslib_color_pink300">#ff8bcb</color>
<color name="settingslib_color_pink100">#fdcfe8</color>
<color name="settingslib_color_purple600">#9334e6</color>
<color name="settingslib_color_purple400">#af5cf7</color>
<color name="settingslib_color_purple300">#c58af9</color>
<color name="settingslib_color_purple100">#e9d2fd</color>
<color name="settingslib_color_cyan600">#12b5c8</color>
<color name="settingslib_color_cyan400">#4ecde6</color>
<color name="settingslib_color_cyan300">#78d9ec</color>
<color name="settingslib_color_cyan100">#cbf0f8</color>
</resources>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Padding of illustration -->
<dimen name="settingslib_illustration_padding">16dp</dimen>
<dimen name="settingslib_illustration_width">412dp</dimen>
<dimen name="settingslib_illustration_height">300dp</dimen>
</resources>

View file

@ -0,0 +1,123 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.util.Pair;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.value.LottieFrameInfo;
import com.airbnb.lottie.value.SimpleLottieValueCallback;
import java.util.HashMap;
import com.android.settingslib.R;
/**
* ColorUtils is a util class which help the lottie illustration
* changes the color of tags in the json file.
*/
public class ColorUtils {
private static HashMap<String, Integer> sSysColors;
private static HashMap<String, Pair<Integer, Integer>> sFixedColors;
static {
sFixedColors = new HashMap<>();
sFixedColors.put(".blue600", new Pair<Integer, Integer>(
R.color.settingslib_color_blue600, R.color.settingslib_color_blue400));
sFixedColors.put(".green600", new Pair<Integer, Integer>(
R.color.settingslib_color_green600, R.color.settingslib_color_green400));
sFixedColors.put(".red600", new Pair<Integer, Integer>(
R.color.settingslib_color_red600, R.color.settingslib_color_red400));
sFixedColors.put(".yellow600", new Pair<Integer, Integer>(
R.color.settingslib_color_yellow600, R.color.settingslib_color_yellow400));
sFixedColors.put(".blue400", new Pair<Integer, Integer>(
R.color.settingslib_color_blue400, R.color.settingslib_color_blue100));
sFixedColors.put(".green400", new Pair<Integer, Integer>(
R.color.settingslib_color_green400, R.color.settingslib_color_green100));
sFixedColors.put(".red400", new Pair<Integer, Integer>(
R.color.settingslib_color_red400, R.color.settingslib_color_red100));
sFixedColors.put(".yellow400", new Pair<Integer, Integer>(
R.color.settingslib_color_yellow400, R.color.settingslib_color_yellow100));
sFixedColors.put(".blue300", new Pair<Integer, Integer>(
R.color.settingslib_color_blue300, R.color.settingslib_color_blue50));
sFixedColors.put(".blue50", new Pair<Integer, Integer>(
R.color.settingslib_color_blue50, R.color.settingslib_color_grey900));
sFixedColors.put(".green50", new Pair<Integer, Integer>(
R.color.settingslib_color_green50, R.color.settingslib_color_grey900));
sFixedColors.put(".red50", new Pair<Integer, Integer>(
R.color.settingslib_color_red50, R.color.settingslib_color_grey900));
sFixedColors.put(".yellow50", new Pair<Integer, Integer>(
R.color.settingslib_color_yellow50, R.color.settingslib_color_grey900));
// Secondary colors
sFixedColors.put(".orange600", new Pair<Integer, Integer>(
R.color.settingslib_color_orange600, R.color.settingslib_color_orange300));
sFixedColors.put(".pink600", new Pair<Integer, Integer>(
R.color.settingslib_color_pink600, R.color.settingslib_color_pink300));
sFixedColors.put(".purple600", new Pair<Integer, Integer>(
R.color.settingslib_color_purple600, R.color.settingslib_color_purple300));
sFixedColors.put(".cyan600", new Pair<Integer, Integer>(
R.color.settingslib_color_cyan600, R.color.settingslib_color_cyan300));
sFixedColors.put(".orange400", new Pair<Integer, Integer>(
R.color.settingslib_color_orange400, R.color.settingslib_color_orange100));
sFixedColors.put(".pink400", new Pair<Integer, Integer>(
R.color.settingslib_color_pink400, R.color.settingslib_color_pink100));
sFixedColors.put(".purple400", new Pair<Integer, Integer>(
R.color.settingslib_color_purple400, R.color.settingslib_color_purple100));
sFixedColors.put(".cyan400", new Pair<Integer, Integer>(
R.color.settingslib_color_cyan400, R.color.settingslib_color_cyan100));
sFixedColors.put(".gery400", new Pair<Integer, Integer>(
R.color.settingslib_color_grey400, R.color.settingslib_color_grey700));
sFixedColors.put(".gery300", new Pair<Integer, Integer>(
R.color.settingslib_color_grey300, R.color.settingslib_color_grey600));
sFixedColors.put(".gery200", new Pair<Integer, Integer>(
R.color.settingslib_color_grey200, R.color.settingslib_color_grey800));
}
private static boolean isDarkMode(Context context) {
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
}
/**
* Apply the color of tags to the animation.
*/
public static void applyDynamicColors(Context context, LottieAnimationView animationView) {
for (String key : sFixedColors.keySet()) {
final Pair<Integer, Integer> fixedColorPair = sFixedColors.get(key);
final int color = isDarkMode(context) ? fixedColorPair.second : fixedColorPair.first;
animationView.addValueCallback(
new KeyPath("**", key, "**"),
LottieProperty.COLOR_FILTER,
new SimpleLottieValueCallback<ColorFilter>() {
@Override
public ColorFilter getValue(LottieFrameInfo<ColorFilter> frameInfo) {
return new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
}
}
);
}
}
}

View file

@ -0,0 +1,391 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.RawRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieDrawable;
import java.io.FileNotFoundException;
import java.io.InputStream;
import com.android.settingslib.R;
/**
* IllustrationPreference is a preference that can play lottie format animation
*/
public class IllustrationPreference extends Preference {
private static final String TAG = "IllustrationPreference";
private static final boolean IS_ENABLED_LOTTIE_ADAPTIVE_COLOR = false;
private static final int SIZE_UNSPECIFIED = -1;
private int mMaxHeight = SIZE_UNSPECIFIED;
private int mImageResId;
private boolean mIsAutoScale;
private Uri mImageUri;
private Drawable mImageDrawable;
private View mMiddleGroundView;
private final Animatable2.AnimationCallback mAnimationCallback =
new Animatable2.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
((Animatable) drawable).start();
}
};
private final Animatable2Compat.AnimationCallback mAnimationCallbackCompat =
new Animatable2Compat.AnimationCallback() {
@Override
public void onAnimationEnd(Drawable drawable) {
((Animatable) drawable).start();
}
};
public IllustrationPreference(Context context) {
super(context);
init(context, /* attrs= */ null);
}
public IllustrationPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public IllustrationPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public IllustrationPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final ImageView backgroundView =
(ImageView) holder.findViewById(R.id.background_view);
final FrameLayout middleGroundLayout =
(FrameLayout) holder.findViewById(R.id.middleground_layout);
final LottieAnimationView illustrationView =
(LottieAnimationView) holder.findViewById(R.id.lottie_view);
// To solve the problem of non-compliant illustrations, we set the frame height
// to 300dp and set the length of the short side of the screen to
// the width of the frame.
final int screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
final int screenHeight = getContext().getResources().getDisplayMetrics().heightPixels;
final FrameLayout illustrationFrame = (FrameLayout) holder.findViewById(
R.id.illustration_frame);
final LayoutParams lp = (LayoutParams) illustrationFrame.getLayoutParams();
lp.width = screenWidth < screenHeight ? screenWidth : screenHeight;
illustrationFrame.setLayoutParams(lp);
handleImageWithAnimation(illustrationView);
handleImageFrameMaxHeight(backgroundView, illustrationView);
if (mIsAutoScale) {
illustrationView.setScaleType(mIsAutoScale
? ImageView.ScaleType.CENTER_CROP
: ImageView.ScaleType.CENTER_INSIDE);
}
handleMiddleGroundView(middleGroundLayout);
if (IS_ENABLED_LOTTIE_ADAPTIVE_COLOR) {
ColorUtils.applyDynamicColors(getContext(), illustrationView);
}
}
/**
* Sets the middle ground view to preference. The user
* can overlay a view on top of the animation.
*/
public void setMiddleGroundView(View view) {
if (view != mMiddleGroundView) {
mMiddleGroundView = view;
notifyChanged();
}
}
/**
* Removes the middle ground view of preference.
*/
public void removeMiddleGroundView() {
mMiddleGroundView = null;
notifyChanged();
}
/**
* Enables the auto scale feature of animation view.
*/
public void enableAnimationAutoScale(boolean enable) {
if (enable != mIsAutoScale) {
mIsAutoScale = enable;
notifyChanged();
}
}
/**
* Sets the lottie illustration resource id.
*/
public void setLottieAnimationResId(int resId) {
if (resId != mImageResId) {
resetImageResourceCache();
mImageResId = resId;
notifyChanged();
}
}
/**
* Gets the lottie illustration resource id.
*/
public int getLottieAnimationResId() {
return mImageResId;
}
/**
* Sets the image drawable to display image in {@link LottieAnimationView}.
*
* @param imageDrawable the drawable of an image
*/
public void setImageDrawable(Drawable imageDrawable) {
if (imageDrawable != mImageDrawable) {
resetImageResourceCache();
mImageDrawable = imageDrawable;
notifyChanged();
}
}
/**
* Gets the image drawable from display image in {@link LottieAnimationView}.
*
* @return the drawable of an image
*/
public Drawable getImageDrawable() {
return mImageDrawable;
}
/**
* Sets the image uri to display image in {@link LottieAnimationView}.
*
* @param imageUri the Uri of an image
*/
public void setImageUri(Uri imageUri) {
if (imageUri != mImageUri) {
resetImageResourceCache();
mImageUri = imageUri;
notifyChanged();
}
}
/**
* Gets the image uri from display image in {@link LottieAnimationView}.
*
* @return the Uri of an image
*/
public Uri getImageUri() {
return mImageUri;
}
/**
* Sets the maximum height of the views, still use the specific one if the maximum height was
* larger than the specific height from XML.
*
* @param maxHeight the maximum height of the frame views in terms of pixels.
*/
public void setMaxHeight(int maxHeight) {
if (maxHeight != mMaxHeight) {
mMaxHeight = maxHeight;
notifyChanged();
}
}
private void resetImageResourceCache() {
mImageDrawable = null;
mImageUri = null;
mImageResId = 0;
}
private void handleMiddleGroundView(ViewGroup middleGroundLayout) {
middleGroundLayout.removeAllViews();
if (mMiddleGroundView != null) {
middleGroundLayout.addView(mMiddleGroundView);
middleGroundLayout.setVisibility(View.VISIBLE);
} else {
middleGroundLayout.setVisibility(View.GONE);
}
}
private void handleImageWithAnimation(LottieAnimationView illustrationView) {
if (mImageDrawable != null) {
resetAnimations(illustrationView);
illustrationView.setImageDrawable(mImageDrawable);
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
}
}
if (mImageUri != null) {
resetAnimations(illustrationView);
illustrationView.setImageURI(mImageUri);
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageUri);
}
}
if (mImageResId > 0) {
resetAnimations(illustrationView);
illustrationView.setImageResource(mImageResId);
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageResId);
}
}
}
private void handleImageFrameMaxHeight(ImageView backgroundView, ImageView illustrationView) {
if (mMaxHeight == SIZE_UNSPECIFIED) {
return;
}
final Resources res = backgroundView.getResources();
final int frameWidth = res.getDimensionPixelSize(R.dimen.settingslib_illustration_width);
final int frameHeight = res.getDimensionPixelSize(R.dimen.settingslib_illustration_height);
final int restrictedMaxHeight = Math.min(mMaxHeight, frameHeight);
backgroundView.setMaxHeight(restrictedMaxHeight);
illustrationView.setMaxHeight(restrictedMaxHeight);
// Ensures the illustration view size is smaller than or equal to the background view size.
final float aspectRatio = (float) frameWidth / frameHeight;
illustrationView.setMaxWidth((int) (restrictedMaxHeight * aspectRatio));
}
private void startAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
}
if (drawable instanceof Animatable2) {
((Animatable2) drawable).registerAnimationCallback(mAnimationCallback);
} else if (drawable instanceof Animatable2Compat) {
((Animatable2Compat) drawable).registerAnimationCallback(mAnimationCallbackCompat);
} else if (drawable instanceof AnimationDrawable) {
((AnimationDrawable) drawable).setOneShot(false);
}
((Animatable) drawable).start();
}
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
Uri imageUri) {
final InputStream inputStream =
getInputStreamFromUri(illustrationView.getContext(), imageUri);
illustrationView.setFailureListener(
result -> Log.w(TAG, "Invalid illustration image uri: " + imageUri, result));
illustrationView.setAnimation(inputStream, /* cacheKey= */ null);
illustrationView.setRepeatCount(LottieDrawable.INFINITE);
illustrationView.playAnimation();
}
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
@RawRes int rawRes) {
illustrationView.setFailureListener(
result -> Log.w(TAG, "Invalid illustration resource id: " + rawRes, result));
illustrationView.setAnimation(rawRes);
illustrationView.setRepeatCount(LottieDrawable.INFINITE);
illustrationView.playAnimation();
}
private static void resetAnimations(LottieAnimationView illustrationView) {
resetAnimation(illustrationView.getDrawable());
illustrationView.cancelAnimation();
}
private static void resetAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
}
if (drawable instanceof Animatable2) {
((Animatable2) drawable).clearAnimationCallbacks();
} else if (drawable instanceof Animatable2Compat) {
((Animatable2Compat) drawable).clearAnimationCallbacks();
}
((Animatable) drawable).stop();
}
private static InputStream getInputStreamFromUri(Context context, Uri uri) {
try {
return context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
Log.w(TAG, "Cannot find content uri: " + uri, e);
return null;
}
}
private void init(Context context, AttributeSet attrs) {
setLayoutResource(R.layout.illustration_preference);
mIsAutoScale = false;
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
com.airbnb.lottie.R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
mImageResId = a.getResourceId(com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes, 0);
a.recycle();
}
}
}

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_state_off_color"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
</ripple>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_state_off_color"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
</ripple>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_state_on_color"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
</ripple>

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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_height="wrap_content"
android:layout_width="match_parent"
android:background="?android:attr/colorBackground"
android:orientation="vertical">
<LinearLayout
android:id="@+id/frame"
android:minHeight="@dimen/settingslib_min_switch_bar_height"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_margin="@dimen/settingslib_switchbar_margin"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<TextView
android:id="@+id/switch_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginEnd="@dimen/settingslib_switch_title_margin"
android:layout_marginVertical="@dimen/settingslib_switch_title_margin"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceListItem"
style="@style/MainSwitchText.Settingslib" />
<ImageView
android:id="@+id/restricted_icon"
android:layout_width="@dimen/settingslib_restricted_icon_size"
android:layout_height="@dimen/settingslib_restricted_icon_size"
android:tint="?android:attr/colorAccent"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
android:src="@android:drawable/ic_info"
android:visibility="gone" />
<Switch
android:id="@android:id/switch_widget"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:focusable="false"
android:clickable="false"
android:theme="@style/Switch.SettingsLib"/>
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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_height="wrap_content"
android:layout_width="match_parent">
<TextView
android:id="@+id/switch_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimaryInverse"
android:layout_marginStart="@dimen/settingslib_switchbar_subsettings_margin_start"
android:textAlignment="viewStart"/>
<ImageView
android:id="@+id/restricted_icon"
android:layout_width="@dimen/settingslib_restricted_icon_size"
android:layout_height="@dimen/settingslib_restricted_icon_size"
android:tint="?android:attr/colorAccent"
android:theme="@android:style/Theme.Material"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
android:src="@android:drawable/ic_info"
android:visibility="gone"/>
<Switch
android:id="@android:id/switch_widget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_switchbar_subsettings_margin_end"
android:theme="@style/SwitchBar.Switch.Settingslib"/>
</LinearLayout>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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_height="wrap_content"
android:layout_width="match_parent"
android:importantForAccessibility="no">
<com.android.settingslib.widget.MainSwitchBar
android:id="@+id/settingslib_main_switch_bar"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</FrameLayout>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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.
-->
<resources>
<color name="settingslib_switchbar_switch_track_tint">#82000000</color>
<color name="settingslib_switchbar_switch_thumb_tint">@android:color/black</color>
</resources>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- SwitchBar sub settings margin start / end -->
<dimen name="settingslib_switchbar_subsettings_margin_start">80dp</dimen>
</resources>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- SwitchBar sub settings margin start / end -->
<dimen name="settingslib_switchbar_subsettings_margin_start">128dp</dimen>
<dimen name="settingslib_switchbar_subsettings_margin_end">128dp</dimen>
</resources>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- SwitchBar sub settings margin start / end -->
<dimen name="settingslib_switchbar_subsettings_margin_start">80dp</dimen>
<dimen name="settingslib_switchbar_subsettings_margin_end">80dp</dimen>
</resources>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Size of layout margin -->
<dimen name="settingslib_switchbar_margin">16dp</dimen>
<!-- Size of layout margin left -->
<dimen name="settingslib_switchbar_padding_left">20dp</dimen>
<!-- Size of layout margin right -->
<dimen name="settingslib_switchbar_padding_right">20dp</dimen>
<!-- Minimum width of switch -->
<dimen name="settingslib_min_switch_width">52dp</dimen>
<!-- Minimum width of switch bar -->
<dimen name="settingslib_min_switch_bar_height">72dp</dimen>
<!-- Radius of switch bar -->
<dimen name="settingslib_switch_bar_radius">28dp</dimen>
</resources>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:textSize">20sp</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textColor">@android:color/black</item>
</style>
</resources>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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.
-->
<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<color name="settingslib_switchbar_switch_track_tint">#BFFFFFFF</color>
<color name="settingslib_switchbar_switch_thumb_tint">@android:color/white</color>
<color name="material_grey_600">#ff757575</color>
</resources>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Restricted icon size in switch bar -->
<dimen name="settingslib_restricted_icon_size">@android:dimen/config_restrictedIconSize</dimen>
<!-- Restricted icon in switch bar -->
<dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
<!-- Size of title margin -->
<dimen name="settingslib_switch_title_margin">24dp</dimen>
<!-- SwitchBar sub settings margin start / end -->
<dimen name="settingslib_switchbar_subsettings_margin_start">72dp</dimen>
<dimen name="settingslib_switchbar_subsettings_margin_end">16dp</dimen>
</resources>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="SwitchBar.Switch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:trackTint">@color/settingslib_switchbar_switch_track_tint</item>
<item name="android:thumbTint">@color/settingslib_switchbar_switch_thumb_tint</item>
<item name="android:minHeight">48dp</item>
<item name="android:minWidth">48dp</item>
</style>
</resources>

View file

@ -0,0 +1,303 @@
/*
* Copyright (C) 2020 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.settingslib.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import java.util.ArrayList;
import java.util.List;
import com.android.settingslib.R;
/**
* MainSwitchBar is a View with a customized Switch.
* This component is used as the main switch of the page
* to enable or disable the prefereces on the page.
*/
public class MainSwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener {
private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
@ColorInt
private int mBackgroundColor;
@ColorInt
private int mBackgroundActivatedColor;
protected TextView mTextView;
protected Switch mSwitch;
private Drawable mBackgroundOn;
private Drawable mBackgroundOff;
private Drawable mBackgroundDisabled;
private View mFrameView;
public MainSwitchBar(Context context) {
this(context, null);
}
public MainSwitchBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MainSwitchBar(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public MainSwitchBar(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(R.layout.settingslib_main_switch_bar, this);
if (!true) {
final TypedArray a = context.obtainStyledAttributes(
new int[]{android.R.attr.colorAccent});
mBackgroundActivatedColor = a.getColor(0, 0);
mBackgroundColor = context.getColor(R.color.material_grey_600);
a.recycle();
}
setFocusable(true);
setClickable(true);
mFrameView = findViewById(R.id.frame);
mTextView = (TextView) findViewById(R.id.switch_text);
mSwitch = (Switch) findViewById(android.R.id.switch_widget);
if (true) {
mBackgroundOn = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_on);
mBackgroundOff = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_off);
mBackgroundDisabled = getContext().getDrawable(
R.drawable.settingslib_switch_bar_bg_disabled);
}
addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
setChecked(mSwitch.isChecked());
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/,
0 /*defStyleRes*/);
final CharSequence title = a.getText(
androidx.preference.R.styleable.Preference_android_title);
setTitle(title);
a.recycle();
}
setBackground(true);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
propagateChecked(isChecked);
}
@Override
public boolean performClick() {
return mSwitch.performClick();
}
/**
* Update the switch status
*/
public void setChecked(boolean checked) {
if (mSwitch != null) {
mSwitch.setChecked(checked);
}
setBackground(checked);
}
/**
* Return the status of the Switch
*/
public boolean isChecked() {
return mSwitch.isChecked();
}
/**
* Return the Switch
*/
public final Switch getSwitch() {
return mSwitch;
}
/**
* Set the title text
*/
public void setTitle(CharSequence text) {
if (mTextView != null) {
mTextView.setText(text);
}
}
/**
* Show the MainSwitchBar
*/
public void show() {
setVisibility(View.VISIBLE);
mSwitch.setOnCheckedChangeListener(this);
}
/**
* Hide the MainSwitchBar
*/
public void hide() {
if (isShowing()) {
setVisibility(View.GONE);
mSwitch.setOnCheckedChangeListener(null);
}
}
/**
* Return the displaying status of MainSwitchBar
*/
public boolean isShowing() {
return (getVisibility() == View.VISIBLE);
}
/**
* Adds a listener for switch changes
*/
public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
mSwitchChangeListeners.add(listener);
}
}
/**
* Remove a listener for switch changes
*/
public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
mSwitchChangeListeners.remove(listener);
}
/**
* Enable or disable the text and switch.
*/
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
mTextView.setEnabled(enabled);
mSwitch.setEnabled(enabled);
if (true) {
if (enabled) {
mFrameView.setBackground(isChecked() ? mBackgroundOn : mBackgroundOff);
} else {
mFrameView.setBackground(mBackgroundDisabled);
}
}
}
private void propagateChecked(boolean isChecked) {
setBackground(isChecked);
final int count = mSwitchChangeListeners.size();
for (int n = 0; n < count; n++) {
mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);
}
}
private void setBackground(boolean isChecked) {
if (!true) {
setBackgroundColor(isChecked ? mBackgroundActivatedColor : mBackgroundColor);
} else {
mFrameView.setBackground(isChecked ? mBackgroundOn : mBackgroundOff);
}
}
static class SavedState extends BaseSavedState {
boolean mChecked;
boolean mVisible;
SavedState(Parcelable superState) {
super(superState);
}
/**
* Constructor called from {@link #CREATOR}
*/
private SavedState(Parcel in) {
super(in);
mChecked = (Boolean) in.readValue(null);
mVisible = (Boolean) in.readValue(null);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue(mChecked);
out.writeValue(mVisible);
}
@Override
public String toString() {
return "MainSwitchBar.SavedState{"
+ Integer.toHexString(System.identityHashCode(this))
+ " checked=" + mChecked
+ " visible=" + mVisible + "}";
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.mChecked = mSwitch.isChecked();
ss.mVisible = isShowing();
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
mSwitch.setChecked(ss.mChecked);
setChecked(ss.mChecked);
setBackground(ss.mChecked);
setVisibility(ss.mVisible ? View.VISIBLE : View.GONE);
mSwitch.setOnCheckedChangeListener(ss.mVisible ? this : null);
requestLayout();
}
}

View file

@ -0,0 +1,151 @@
/*
* Copyright (C) 2020 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.settingslib.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.Switch;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.TwoStatePreference;
import java.util.ArrayList;
import java.util.List;
import com.android.settingslib.R;
/**
* MainSwitchPreference is a Preference with a customized Switch.
* This component is used as the main switch of the page
* to enable or disable the prefereces on the page.
*/
public class MainSwitchPreference extends TwoStatePreference implements OnMainSwitchChangeListener {
private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
private MainSwitchBar mMainSwitchBar;
private CharSequence mTitle;
public MainSwitchPreference(Context context) {
super(context);
init(context, null);
}
public MainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public MainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
holder.setDividerAllowedAbove(false);
holder.setDividerAllowedBelow(false);
mMainSwitchBar = (MainSwitchBar) holder.findViewById(R.id.settingslib_main_switch_bar);
updateStatus(isChecked());
registerListenerToSwitchBar();
}
private void init(Context context, AttributeSet attrs) {
setLayoutResource(R.layout.settingslib_main_switch_layout);
mSwitchChangeListeners.add(this);
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/,
0 /*defStyleRes*/);
final CharSequence title = a.getText(
androidx.preference.R.styleable.Preference_android_title);
setTitle(title);
a.recycle();
}
}
@Override
public void setChecked(boolean checked) {
super.setChecked(checked);
if (mMainSwitchBar != null && mMainSwitchBar.isChecked() != checked) {
mMainSwitchBar.setChecked(checked);
}
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
if (mMainSwitchBar != null) {
mMainSwitchBar.setTitle(mTitle);
}
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
super.setChecked(isChecked);
}
/**
* Update the switch status of preference
*/
public void updateStatus(boolean checked) {
setChecked(checked);
if (mMainSwitchBar != null) {
mMainSwitchBar.setTitle(mTitle);
mMainSwitchBar.show();
}
}
/**
* Adds a listener for switch changes
*/
public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
if (mMainSwitchBar == null) {
mSwitchChangeListeners.add(listener);
} else {
mMainSwitchBar.addOnSwitchChangeListener(listener);
}
}
/**
* Remove a listener for switch changes
*/
public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
if (mMainSwitchBar == null) {
mSwitchChangeListeners.remove(listener);
} else {
mMainSwitchBar.removeOnSwitchChangeListener(listener);
}
}
private void registerListenerToSwitchBar() {
for (OnMainSwitchChangeListener listener : mSwitchChangeListeners) {
mMainSwitchBar.addOnSwitchChangeListener(listener);
}
mSwitchChangeListeners.clear();
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 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.settingslib.widget;
import android.widget.Switch;
/**
* Called when the checked state of the Switch has changed.
*/
public interface OnMainSwitchChangeListener {
/**
* @param switchView The Switch view whose state has changed.
* @param isChecked The new checked state of switchView.
*/
void onSwitchChanged(Switch switchView, boolean isChecked);
}

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingBottom="16dp"
android:paddingTop="8dp"
android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:longClickable="false"
android:maxLines="10"
android:textAppearance="@style/TextAppearance.TopIntroText"/>
</LinearLayout>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="TextAppearance.TopIntroText"
parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
</resources>

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 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.settingslib.widget;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.R;
/**
* The TopIntroPreference shows a text which describe a feature. Gernerally, we expect this
* preference always shows on the top of screen.
*/
public class TopIntroPreference extends Preference {
public TopIntroPreference(Context context) {
super(context);
setLayoutResource(R.layout.top_intro_preference);
setSelectable(false);
}
public TopIntroPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.top_intro_preference);
setSelectable(false);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
holder.setDividerAllowedAbove(false);
holder.setDividerAllowedBelow(false);
}
}

32
SettingsLib/build.gradle Normal file
View file

@ -0,0 +1,32 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 32
sourceSets.main {
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['res']
res.srcDirs = [
'main/res',
'CollapsingToolbarBaseActivity/res',
'IllustrationPreference/res',
'TopIntroPreference/res',
'MainSwitchPreference/res',
]
java.srcDirs = [
'CollapsingToolbarBaseActivity/src',
'IllustrationPreference/src',
'TopIntroPreference/src',
'MainSwitchPreference/src',
]
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'com.airbnb.android:lottie:5.2.0'
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/system_accent2_500" android:lStar="51" />
</selector>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/system_neutral1_500" android:lStar="98" />
</selector>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Disabled status of thumb -->
<item android:state_enabled="false"
android:color="@color/settingslib_thumb_disabled_color" />
<!-- Toggle off status of thumb -->
<item android:state_checked="false"
android:color="@color/settingslib_thumb_off_color" />
<!-- Enabled or toggle on status of thumb -->
<item android:color="@color/settingslib_state_on_color" />
</selector>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Disabled status of thumb -->
<item android:state_enabled="false"
android:color="@color/settingslib_track_off_color"
android:alpha="?android:attr/disabledAlpha" />
<!-- Toggle off status of thumb -->
<item android:state_checked="false"
android:color="@color/settingslib_track_off_color" />
<!-- Enabled or toggle on status of thumb -->
<item android:color="@color/settingslib_track_on_color" />
</selector>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/system_neutral2_500" android:lStar="45" />
</selector>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@android:id/background">
<shape>
<corners android:radius="8dp" />
<solid android:color="@color/settingslib_colorSurfaceVariant" />
</shape>
</item>
<item
android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="8dp" />
<solid android:color="?android:attr/textColorPrimary" />
</shape>
</clip>
</item>
</layer-list>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="4dp"
android:left="4dp"
android:right="4dp"
android:bottom="4dp">
<shape android:shape="oval" >
<size android:height="20dp" android:width="20dp" />
<solid android:color="@color/settingslib_switch_thumb_color" />
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:width="52dp"
android:height="28dp">
<solid android:color="@color/settingslib_switch_track_color" />
<corners android:radius="35dp" />
</shape>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<!-- We use a FrameLayout as we want to place the invisible spinner on top of the other views -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- This spinner should be invisible in the layout and take up no space, when the Preference
is clicked the dropdown will appear from this location on screen. -->
<Spinner
android:id="@+id/spinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/preference_dropdown_padding_start"
android:layout_marginLeft="@dimen/preference_dropdown_padding_start"
android:visibility="invisible" />
<include layout="@layout/settingslib_preference" />
</FrameLayout>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:gravity="start|center_vertical"
android:orientation="horizontal"
android:paddingLeft="0dp"
android:paddingStart="0dp"
android:paddingRight="8dp"
android:paddingEnd="8dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<androidx.preference.internal.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:maxWidth="48dp"
app:maxHeight="48dp"/>
</LinearLayout>

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false"
android:baselineAligned="false">
<include layout="@layout/settingslib_icon_frame"/>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
android:layout_alignStart="@android:id/title"
android:layout_gravity="start"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"
style="@style/PreferenceSummaryTextStyle"/>
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="end|center_vertical"
android:paddingLeft="16dp"
android:paddingStart="16dp"
android:paddingRight="0dp"
android:paddingEnd="0dp"
android:orientation="vertical"/>
</LinearLayout>

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Material next thumb disable color-->
<color name="settingslib_thumb_disabled_color">@android:color/system_neutral1_700</color>
<!-- Material next thumb off color-->
<color name="settingslib_thumb_off_color">@android:color/system_neutral1_400</color>
<!-- Material next track on color-->
<color name="settingslib_track_on_color">@color/settingslib_switch_track_on</color>
<!-- Material next track off color-->
<color name="settingslib_track_off_color">@android:color/system_neutral1_700</color>
<!-- Dialog accent color -->
<color name="settingslib_dialog_accent">@android:color/system_accent1_100</color>
<!-- Dialog background color. -->
<color name="settingslib_dialog_background">@android:color/system_neutral1_800</color>
<!-- Dialog error color. -->
<color name="settingslib_dialog_colorError">#f28b82</color> <!-- Red 300 -->
<color name="settingslib_colorSurfaceVariant">@android:color/system_neutral1_700</color>
<color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_700</color>
<!-- copy from accent_primary_variant_dark_device_default-->
<color name="settingslib_accent_primary_variant">@android:color/system_accent1_300</color>
<color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_50</color>
</resources>

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Material next state on color-->
<color name="settingslib_state_on_color">@android:color/system_accent1_100</color>
<!-- Material next state off color-->
<color name="settingslib_state_off_color">@android:color/system_accent2_100</color>
<!-- Material next thumb disable color-->
<color name="settingslib_thumb_disabled_color">@android:color/system_neutral2_100</color>
<!-- Material next thumb off color-->
<color name="settingslib_thumb_off_color">@android:color/system_neutral2_300</color>
<!-- Material next track on color-->
<color name="settingslib_track_on_color">@android:color/system_accent1_600</color>
<!-- Material next track off color-->
<color name="settingslib_track_off_color">@color/settingslib_switch_track_off</color>
<!-- Dialog accent color -->
<color name="settingslib_dialog_accent">@android:color/system_accent1_600</color>
<!-- Dialog background color -->
<color name="settingslib_dialog_background">@color/settingslib_surface_light</color>
<!-- Dialog error color. -->
<color name="settingslib_dialog_colorError">#d93025</color> <!-- Red 600 -->
<color name="settingslib_colorSurfaceVariant">@android:color/system_neutral2_100</color>
<color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_100</color>
<color name="settingslib_accent_device_default_dark">@android:color/system_accent1_100</color>
<color name="settingslib_accent_device_default_light">@android:color/system_accent1_600</color>
<color name="settingslib_primary_dark_device_default_settings">@android:color/system_neutral1_900</color>
<color name="settingslib_primary_device_default_settings_light">@android:color/system_neutral1_50</color>
<color name="settingslib_accent_primary_device_default">@android:color/system_accent1_100</color>
<!-- copy from accent_primary_variant_light_device_default-->
<color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color>
<color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color>
<color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color>
<color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
<color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color>
</resources>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<bool name="settingslib_config_icon_space_reserved">false</bool>
<bool name="settingslib_config_allow_divider">false</bool>
</resources>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<resources>
<dimen name="app_preference_padding_start">20dp</dimen>
<dimen name="app_icon_min_width">52dp</dimen>
<dimen name="settingslib_preferred_minimum_touch_target">48dp</dimen>
<dimen name="settingslib_dialogCornerRadius">28dp</dimen>
</resources>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Name of a font family to use for headlines in SettingsLib. -->
<string name="settingslib_config_headlineFontFamily" translatable="false">
@*android:string/config_headlineFontFamily
</string>
<!-- Name of a font family to use for headlines-medium in SettingsLib. -->
<string name="settingslib_config_headlineFontFamilyMedium" translatable="false">
@*android:string/config_headlineFontFamilyMedium
</string>
<!-- Name of a font family to use for body in SettingsLib. -->
<string name="settingslib_config_bodyFontFamily" translatable="false">
@*android:string/config_bodyFontFamily
</string>
<!-- Name of a font family to use for body-medium in SettingsLib. -->
<string name="settingslib_config_bodyFontFamilyMedium" translatable="false">
@*android:string/config_bodyFontFamilyMedium
</string>
</resources>

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="PreferenceTheme.SettingsLib" parent="@style/PreferenceThemeOverlay">
<item name="preferenceCategoryTitleTextAppearance">@style/TextAppearance.CategoryTitle.SettingsLib</item>
<item name="preferenceCategoryStyle">@style/SettingsCategoryPreference.SettingsLib</item>
<item name="preferenceStyle">@style/SettingsPreference.SettingsLib</item>
<item name="checkBoxPreferenceStyle">@style/SettingsCheckBoxPreference.SettingsLib</item>
<item name="dialogPreferenceStyle">@style/SettingsPreference.SettingsLib</item>
<item name="editTextPreferenceStyle">@style/SettingsEditTextPreference.SettingsLib</item>
<item name="dropdownPreferenceStyle">@style/SettingsDropdownPreference.SettingsLib</item>
<item name="switchPreferenceStyle">@style/SettingsSwitchPreference.SettingsLib</item>
<item name="seekBarPreferenceStyle">@style/SettingsSeekbarPreference.SettingsLib</item>
<item name="footerPreferenceStyle">@style/Preference.Material</item>
</style>
<style name="SettingsCategoryPreference.SettingsLib" parent="@style/Preference.Category.Material">
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
<item name="allowDividerAbove">@bool/settingslib_config_allow_divider</item>
<item name="allowDividerBelow">@bool/settingslib_config_allow_divider</item>
</style>
<style name="SettingsPreference.SettingsLib" parent="@style/Preference.Material">
<item name="layout">@layout/settingslib_preference</item>
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
<style name="SettingsCheckBoxPreference.SettingsLib" parent="@style/Preference.CheckBoxPreference.Material">
<item name="layout">@layout/settingslib_preference</item>
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
<style name="SettingsEditTextPreference.SettingsLib"
parent="@style/Preference.DialogPreference.EditTextPreference.Material">
<item name="layout">@layout/settingslib_preference</item>
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
<style name="SettingsDropdownPreference.SettingsLib" parent="@style/Preference.DropDown.Material">
<item name="layout">@layout/settingslib_dropdown_preference</item>
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
<style name="SettingsSwitchPreference.SettingsLib" parent="@style/Preference.SwitchPreference.Material">
<item name="layout">@layout/settingslib_preference</item>
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
<style name="SettingsSeekbarPreference.SettingsLib" parent="@style/Preference.SeekBarPreference.Material">
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
</resources>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
<style name="TextAppearance.CategoryTitle.SettingsLib"
parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">14sp</item>
</style>
<style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:switchMinWidth">52dp</item>
<item name="android:minHeight">@dimen/settingslib_preferred_minimum_touch_target</item>
<item name="android:track">@drawable/settingslib_switch_track</item>
<item name="android:thumb">@drawable/settingslib_switch_thumb</item>
</style>
<style name="HorizontalProgressBar.SettingsLib"
parent="android:style/Widget.Material.ProgressBar.Horizontal">
<item name="android:progressDrawable">@drawable/settingslib_progress_horizontal</item>
<item name="android:scaleY">0.5</item>
</style>
</resources>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Only using in Settings application -->
<style name="Theme.SettingsBase" parent="@android:style/Theme.DeviceDefault.Settings" >
<item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle.SettingsLib</item>
<item name="android:listPreferredItemPaddingStart">24dp</item>
<item name="android:listPreferredItemPaddingLeft">24dp</item>
<item name="android:listPreferredItemPaddingEnd">16dp</item>
<item name="android:listPreferredItemPaddingRight">16dp</item>
<item name="preferenceTheme">@style/PreferenceTheme.SettingsLib</item>
<item name="android:switchStyle">@style/Switch.SettingsLib</item>
<item name="android:progressBarStyleHorizontal">@style/HorizontalProgressBar.SettingsLib</item>
</style>
<!-- Using in SubSettings page including injected settings page -->
<style name="Theme.SubSettingsBase" parent="Theme.SettingsBase">
<!-- Suppress the built-in action bar -->
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<!-- Set up edge-to-edge configuration for top app bar -->
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="colorControlNormal">?android:attr/colorControlNormal</item>
<!-- For AndroidX AlertDialog -->
<item name="alertDialogTheme">@style/Theme.AlertDialog.SettingsLib</item>
</style>
<style name="Theme.AlertDialog.SettingsLib" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
<item name="colorAccent">@color/settingslib_dialog_accent</item>
<item name="android:colorError">@color/settingslib_dialog_colorError</item>
<item name="android:colorBackground">@color/settingslib_dialog_background</item>
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="android:clipToPadding">true</item>
<item name="android:clipChildren">true</item>
<item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
</style>
</resources>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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.
-->
<resources>
<attr name="footerPreferenceStyle" format="reference" />
</resources>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<resources>
<dimen name="secondary_app_icon_size">32dp</dimen>
<dimen name="app_preference_padding_start">?android:attr/listPreferredItemPaddingStart</dimen>
<dimen name="app_icon_min_width">56dp</dimen>
<dimen name="two_target_min_width">72dp</dimen>
<dimen name="settingslib_dialogCornerRadius">8dp</dimen>
</resources>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- Only using in Settings application -->
<style name="Theme.SettingsBase" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>
<!-- Using in SubSettings page including injected settings page -->
<style name="Theme.SubSettingsBase" parent="Theme.SettingsBase">
<!-- Suppress the built-in action bar -->
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="colorControlNormal">?android:attr/colorControlNormal</item>
<!-- For AndroidX AlertDialog -->
<item name="alertDialogTheme">@style/Theme.AlertDialog.SettingsLib</item>
</style>
<style name="Theme.AlertDialog.SettingsLib" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
<!-- TODO(b/189308264): fix the crash in Android R if set the attributes:
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="android:colorBackground">@color/settingslib_dialog_background</item>
<item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
-->
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="android:clipToPadding">true</item>
<item name="android:clipChildren">true</item>
</style>
</resources>

63
build.gradle Normal file
View file

@ -0,0 +1,63 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
}
}
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
apply plugin: 'com.android.application'
android {
compileSdkVersion 32
defaultConfig {
minSdkVersion 32
targetSdkVersion 32
}
sourceSets {
main {
res.srcDirs = ['res']
java.srcDirs = ['src']
manifest.srcFile 'AndroidManifest.xml'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
signingConfigs {
debug {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
lint {
ignore 'ProtectedPermissions', 'ExtraTranslation', 'ImpliedQuantity', 'MissingQuantity', 'MissingTranslation'
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.preference:preference:1.1.0'
implementation project(path: ':SettingsLib')
implementation files('libs/vendor.mediatek.hardware.aguiledbelt-V1.0-java.jar')
// This is only here to allow vendor.mediatek.hardware.aguiledbelt-V1.0-java to compile properly
// It does not reveal all hidden API interfaces in Android Studio; unfortunately
compileOnly files('libs/framework.jar')
}

4
gradle.properties Normal file
View file

@ -0,0 +1,4 @@
android.enableJetifier=true
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,6 @@
#Mon Feb 14 17:28:09 IRST 2022
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip

183
gradlew vendored Executable file
View file

@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

100
gradlew.bat vendored Normal file
View file

@ -0,0 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,4 @@
keyAlias=android
keyPassword=android
storeFile=testkey.jks
storePassword=android

BIN
libs/framework.jar Normal file

Binary file not shown.

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 Paranoid Android
~
~ 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
-->
<permissions>
<privapp-permissions package="com.volla.spotlight">
<permission name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
<permission name="android.permission.READ_PHONE_STATE"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
</privapp-permissions>
</permissions>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 Paranoid Android
~
~ 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
-->
<config>
<allow-in-power-save package="com.volla.spotlight" />
</config>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:tint="?android:attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M12,0C15.182,0.002 18.231,1.268 20.482,3.518C22.73,5.769 23.996,8.818 24,12C24,15.182 22.735,18.236 20.486,20.484C18.236,22.735 15.182,24 12,24C8.818,24 5.764,22.735 3.514,20.484C1.265,18.236 0,15.182 0,12C0,8.818 1.265,5.764 3.514,3.514C5.764,1.265 8.818,0 12,0ZM12,1.708C9.271,1.708 6.652,2.793 4.724,4.724C2.793,6.652 1.708,9.272 1.708,12C1.708,14.729 2.793,17.348 4.724,19.277C6.651,21.207 9.271,22.292 12,22.292C14.729,22.288 17.344,21.202 19.274,19.274C21.202,17.344 22.288,14.729 22.292,12C22.292,9.272 21.207,6.652 19.276,4.724C17.349,2.793 14.729,1.708 12,1.708ZM12,3.369C14.289,3.371 16.481,4.283 18.1,5.9C19.717,7.519 20.629,9.712 20.631,12C20.631,14.289 19.722,16.484 18.103,18.103C16.483,19.722 14.289,20.631 12,20.631C9.711,20.631 7.516,19.722 5.897,18.103C4.279,16.484 3.369,14.289 3.369,12C3.369,9.712 4.278,7.517 5.897,5.898C7.517,4.279 9.712,3.369 12,3.369ZM14.649,5.604C12.063,4.532 9.085,5.126 7.105,7.105C5.126,9.084 4.533,12.062 5.604,14.649C6.676,17.235 9.2,18.923 12,18.923L12,18.923L12.238,18.918C15.949,18.789 18.919,15.741 18.923,12C18.923,9.2 17.235,6.676 14.649,5.604Z" android:fillType="evenOdd" />
</vector>

54
res/values/strings.xml Normal file
View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013-2016 The CyanogenMod Project
2017 The LineageOS Project
2020-2022 Paranoid Android
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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- DO NOT TRANSLATE Empty summary for dynamic preferences -->
<string name="summary_empty" translatable="false"></string>
<!-- App Name -->
<string name="spotlight_settings_app_name">Lunatic LED interface</string>
<!-- Ambient Display -->
<string name="spotlight_settings_enable">Enable LEDs</string>
<string name="spotlight_settings_title">Lunatic LED interface</string>
<string name="spotlight_settings_summary">Options for Lunatic LEDs</string>
<string name="spotlight_settings_brightness">Brightness</string>
<string name="spotlight_settings_charging_title">Charging animation</string>
<string name="spotlight_settings_charging_level_title">Battery level</string>
<string name="spotlight_settings_charging_level_summary">Show battery level when plugging in</string>
<string name="spotlight_settings_call_title">Calls</string>
<string name="spotlight_settings_call_toggle_title">Call animation</string>
<string name="spotlight_settings_call_toggle_summary">Flash LEDs on incoming calls</string>
<string name="spotlight_settings_notifs_title">Notifications</string>
<string name="spotlight_settings_notifs_toggle_title">Notification animation</string>
<string name="spotlight_settings_notifs_toggle_summary">Flash LEDs on new notifications</string>
<string name="spotlight_settings_notifs_sub_title">Apps to allow</string>
<string name="spotlight_settings_notifs_sub_toggle_title">Enable notification animation</string>
<string name="spotlight_settings_flashlight_toggle_title">Flashlight</string>
<string name="spotlight_settings_flashlight_toggle_summary">Flash LEDs when using the flashlight</string>
<string name="spotlight_settings_music_toggle_title">Music animation</string>
<string name="spotlight_settings_music_toggle_summary">Flash LEDs when music is playing</string>
</resources>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2022 Paranoid Android
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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/spotlight_settings_notifs_toggle_title">
<com.android.settingslib.widget.MainSwitchPreference
android:key="spotlight_settings_notifs_sub_toggle"
android:title="@string/spotlight_settings_notifs_sub_toggle_title" />
<PreferenceCategory
android:key="spotlight_settings_notifs_sub"
android:title="@string/spotlight_settings_notifs_sub_title" />
</PreferenceScreen>

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The CyanogenMod Project
2018-2019 The LineageOS Project
2020-2022 Paranoid Android
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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/spotlight_settings_title">
<com.android.settingslib.widget.MainSwitchPreference
android:defaultValue="false"
android:key="spotlight_enable"
android:title="@string/spotlight_settings_enable" />
<SeekBarPreference
android:key="spotlight_settings_brightness"
android:max="100"
android:defaultValue="100"
android:title="@string/spotlight_settings_brightness" />
<SwitchPreference
android:key="spotlight_settings_call_toggle"
android:defaultValue="true"
android:title="@string/spotlight_settings_call_toggle_title"
android:summary="@string/spotlight_settings_call_toggle_summary" />
<SwitchPreference
android:key="spotlight_settings_notifs_toggle"
android:defaultValue="false"
android:title="@string/spotlight_settings_notifs_toggle_title"
android:summary="@string/spotlight_settings_notifs_toggle_summary" >
<intent android:action="android.intent.action.MAIN"
android:targetPackage="net.typeblog.lunatic"
android:targetClass="net.typeblog.lunatic.Settings.NotifsSettingsActivity"/>
</SwitchPreference>
<SwitchPreference
android:key="spotlight_settings_charging_level"
android:defaultValue="true"
android:title="@string/spotlight_settings_charging_level_title"
android:summary="@string/spotlight_settings_charging_level_summary" />
<SwitchPreference
android:key="spotlight_settings_flashlight_toggle"
android:defaultValue="true"
android:title="@string/spotlight_settings_flashlight_toggle_title"
android:summary="@string/spotlight_settings_flashlight_toggle_summary" />
<SwitchPreference
android:key="spotlight_settings_music_toggle"
android:defaultValue="true"
android:title="@string/spotlight_settings_music_toggle_title"
android:summary="@string/spotlight_settings_music_toggle_summary" />
</PreferenceScreen>

15
settings.gradle Normal file
View file

@ -0,0 +1,15 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
include ':SettingsLib'

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2019 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import net.typeblog.lunatic.Utils.ServiceUtils;
public class BootCompletedReceiver extends BroadcastReceiver {
private static final boolean DEBUG = true;
private static final String TAG = "ParanoidSpotlight";
@Override
public void onReceive(final Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Received boot completed intent");
ServiceUtils.checkSpotlightService(context);
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Constants;
public final class Constants {
private static final String TAG = "SpotlightConstants";
private static final boolean DEBUG = true;
public static float BRIGHTNESS = 1;
public static final String SPOTLIGHT_ENABLE = "spotlight_enable";
public static final String SPOTLIGHT_BRIGHTNESS = "spotlight_settings_brightness";
public static final String SPOTLIGHT_CHARGING_LEVEL_ENABLE = "spotlight_settings_charging_level";
public static final String SPOTLIGHT_FLASHLIGHT_ENABLE = "spotlight_settings_flashlight_toggle";
public static final String SPOTLIGHT_MUSIC_ENABLE = "spotlight_settings_music_toggle";
public static final String SPOTLIGHT_CALL_ENABLE = "spotlight_settings_call_toggle";
public static final String SPOTLIGHT_NOTIFS_ENABLE = "spotlight_settings_notifs_toggle";
public static final String SPOTLIGHT_NOTIFS_SUB_CATEGORY = "spotlight_settings_notifs_sub";
public static final String SPOTLIGHT_NOTIFS_SUB_ENABLE = "spotlight_settings_notifs_sub_toggle";
public enum SpotlightMode {
FLASHLIGHT,
CALLS,
MUSIC,
NOTIFICATIONS,
CHARGING,
}
public static final String[] APPSTOIGNORE = {
"android",
"com.android.traceur",
//"com.google.android.dialer",
"com.google.android.setupwizard",
"dev.kdrag0n.dyntheme.privileged.sys"
};
public static final String[] NOTIFSTOIGNORE = {
"com.google.android.dialer:phone_incoming_call",
"com.google.android.dialer:phone_ongoing_call"
};
public static void setBrightness(float b) {
BRIGHTNESS = b;
}
}

View file

@ -0,0 +1,311 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Manager;
import android.content.Context;
import android.media.audiofx.Visualizer;
import android.os.BatteryManager;
import android.util.Log;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import net.typeblog.lunatic.Constants.Constants;
public final class AnimationManager {
private static final String TAG = "SpotlightAnimationManager";
private static final boolean DEBUG = true;
private Context mContext;
private LEDManager mLEDManager;
private BatteryManager mBatteryManager;
private Visualizer mVisualizer;
public AnimationManager(Context context) {
mContext = context;
mLEDManager = new LEDManager();
}
private static Future<?> submit(Runnable runnable) {
ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
return mExecutorService.submit(runnable);
}
private static boolean check(Constants.SpotlightMode mode) {
switch (mode) {
case FLASHLIGHT:
if (!StatusManager.isAllLedsActive())
return false;
break;
case CALLS:
if (StatusManager.isAllLedsActive()) {
if (DEBUG) Log.d(TAG, "All LEDs are active, can\'t start animation | name: " + mode.name());
return false;
}
if (!StatusManager.isCallLedsActive())
return false;
break;
case MUSIC:
if (StatusManager.isAllLedsActive() || StatusManager.isCallLedsActive()) {
if (DEBUG) Log.d(TAG, "Call or All LEDs are active, can\'t start animation | name: " + mode.name());
return false;
}
if (!StatusManager.isMusicLedsActive())
return false;
break;
case NOTIFICATIONS:
if (StatusManager.isAllLedsActive() || StatusManager.isCallLedsActive() || StatusManager.isMusicLedsActive()) {
if (DEBUG) Log.d(TAG, "Call, Music or All LEDs are active, can\'t start animation | name: " + mode.name());
return false;
}
if (!StatusManager.isNotifLedsActive())
return false;
break;
case CHARGING:
if (StatusManager.isAllLedsActive() || StatusManager.isCallLedsActive() || StatusManager.isMusicLedsActive() || StatusManager.isNotifLedsActive()) {
if (DEBUG) Log.d(TAG, "Call, Music, Notification or All LEDs are active, can\'t start animation | name: " + mode.name());
return false;
}
if (!StatusManager.isChargingLedsActive())
return false;
break;
}
return true;
}
private void cleanupAndContinue() {
mLEDManager.enableAllLEDs(false);
if (StatusManager.isAllLedsActive()) {
playFlashlight();
} else if (StatusManager.isCallLedsActive()) {
playCall();
} else if (StatusManager.isMusicLedsActive()) {
playMusic();
} else if (StatusManager.isNotifLedsActive()) {
playNotifications();
} else if (StatusManager.isChargingLedsActive()) {
playCharging();
}
}
private int getBatteryLevel() {
mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
return mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
}
public void playCharging() {
StatusManager.setChargingLedsActive(true);
submit(() -> {
int solid_leds = 0;
mLEDManager.enableAllLEDs(false);
mLEDManager.setBrightness((int) (Constants.BRIGHTNESS * 100));
try {
int oldBatteryLevel = -1;
while (check(Constants.SpotlightMode.CHARGING)) {
int batteryLevel = getBatteryLevel();
if (oldBatteryLevel != batteryLevel) {
solid_leds = Integer.valueOf(batteryLevel / mLEDManager.getNumLEDs());
for (int i = 0; i < solid_leds; i++) {
mLEDManager.enableLED(i, true);
Thread.sleep(150);
}
oldBatteryLevel = batteryLevel;
}
if (100 - solid_leds * mLEDManager.getNumLEDs() > 0) {
mLEDManager.enableLED(solid_leds, true);
Thread.sleep(500);
mLEDManager.enableLED(solid_leds, false);
Thread.sleep(500);
}
}
} catch (InterruptedException e) {
Log.e(TAG, "Error while playing charging animation", e);
}
mLEDManager.enableAllLEDs(false);
});
}
public void stopCharging() {
if (DEBUG) Log.d(TAG, "Done playing animation | name: charging");
StatusManager.setChargingLedsActive(false);
cleanupAndContinue();
}
public void playCall() {
StatusManager.setCallLedsActive(true);
submit(() -> {
mLEDManager.enableAllLEDs(false);
mLEDManager.setBrightness((int) (Constants.BRIGHTNESS * 100));
try {
boolean enableOdds = false;
while (check(Constants.SpotlightMode.CALLS)) {
for (int i = 0; i < mLEDManager.getNumLEDs(); i++) {
if (i % 2 == (enableOdds ? 1 : 0)) {
mLEDManager.enableLED(i, true);
} else {
mLEDManager.enableLED(i, false);
}
}
enableOdds = !enableOdds;
Thread.sleep(500);
}
} catch (InterruptedException e) {
Log.e(TAG, "Error while playing charging animation", e);
}
mLEDManager.enableAllLEDs(false);
});
}
public void stopCall() {
if (DEBUG) Log.d(TAG, "Disabling Call Animation");
StatusManager.setCallLedsActive(false);
cleanupAndContinue();
}
public void playNotifications() {
StatusManager.setNotifLedsActive(true);
if (DEBUG) Log.d(TAG, "Trying to play notification effect");
submit(() -> {
if (!check(Constants.SpotlightMode.NOTIFICATIONS))
return;
if (DEBUG) Log.d(TAG, "Playing notification effect");
try {
mLEDManager.setBrightness((int) (Constants.BRIGHTNESS * 100));
mLEDManager.enableAllLEDs(true);
Thread.sleep(35);
mLEDManager.enableAllLEDs(false);
Thread.sleep(35);
mLEDManager.enableAllLEDs(true);
Thread.sleep(35);
mLEDManager.enableAllLEDs(false);
} catch (InterruptedException e) {
mLEDManager.enableAllLEDs(false);
}
});
}
public void stopNotifications() {
if (DEBUG) Log.d(TAG, "Disabling Notifications Animation");
StatusManager.setNotifLedsActive(false);
cleanupAndContinue();
}
public void playFlashlight() {
StatusManager.setAllLedsActive(true);
submit(() -> {
if (check(Constants.SpotlightMode.FLASHLIGHT)) {
mLEDManager.setBrightness((int) (Constants.BRIGHTNESS * 100));
mLEDManager.enableAllLEDs(true);
}
});
}
public void stopFlashlight() {
if (DEBUG) Log.d(TAG, "Disabling Flashlight");
StatusManager.setAllLedsActive(false);
cleanupAndContinue();
}
private Visualizer.OnDataCaptureListener mVisualizerListener =
new Visualizer.OnDataCaptureListener() {
float rfk, ifk;
float dbValue;
float maxDbValue = 0;
float magnitude;
boolean isAnimating = false;
long lastColorChange = 0;
@Override
public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) {
}
@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
if (isAnimating) return;
if (!check(Constants.SpotlightMode.MUSIC))
return;
submit(() -> {
isAnimating = true;
int enabledLEDs = 0;
for (int i = 0; i < mLEDManager.getNumLEDs(); i++) {
rfk = fft[i * 2 + 2]/128.0f;
ifk = fft[i * 2 + 3]/128.0f;
magnitude = rfk * rfk + ifk * ifk;
dbValue = magnitude > 1 ? 1 : magnitude;
if (i == 0) {
// Use the lowest frequency component as the overall brightness
mLEDManager.setBrightness((int) (dbValue * Constants.BRIGHTNESS * 100));
}
if (dbValue > 0.5) {
enabledLEDs++;
mLEDManager.enableLED(mLEDManager.getNumLEDs() - i - 1, true);
} else {
mLEDManager.enableLED(mLEDManager.getNumLEDs() - i - 1, false);
}
}
if (enabledLEDs == 0 && System.currentTimeMillis() - lastColorChange > 1000) {
mLEDManager.setColor(ThreadLocalRandom.current().nextInt(0xffffff));
lastColorChange = System.currentTimeMillis();
}
isAnimating = false;
});
}
};
public void playMusic() {
StatusManager.setMusicLedsActive(true);
try {
mVisualizer = new Visualizer(0);
} catch (Exception e) {
Log.e(TAG, "error initializing visualizer", e);
return;
}
mVisualizer.setEnabled(false);
mVisualizer.setCaptureSize(66);
mVisualizer.setDataCaptureListener(mVisualizerListener, Visualizer.getMaxCaptureRate(),
false, true);
mVisualizer.setEnabled(true);
}
public void stopMusic() {
if (DEBUG) Log.d(TAG, "Disabling Music animation");
StatusManager.setMusicLedsActive(false);
if (mVisualizer != null) {
mVisualizer.setEnabled(false);
mVisualizer.release();
mVisualizer = null;
}
cleanupAndContinue();
}
}

View file

@ -0,0 +1,67 @@
package net.typeblog.lunatic.Manager;
import android.os.RemoteException;
import vendor.mediatek.hardware.aguiledbelt.V1_0.IAguiLedBeltLight;
public class LEDManager {
private static IAguiLedBeltLight sCtrl = null;
private int mColor = 0xffffff;
private int mBrightness = 100;
private int mEnabledLeds = 0;
private IAguiLedBeltLight ensureService() {
if (sCtrl == null) {
try {
sCtrl = IAguiLedBeltLight.getService(true);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
return sCtrl;
}
private void syncState() {
try {
ensureService().setLedBeltAlwaysOnState(mEnabledLeds, mColor, mBrightness, false);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
public int getNumLEDs() {
return 5;
}
public void enableLED(int ledno, boolean enabled) {
if (enabled) {
mEnabledLeds |= 1 << ledno;
} else {
mEnabledLeds &= ~(1 << ledno);
}
syncState();
}
public void setBrightness(int brightness) {
if (brightness > 100) {
brightness = 100;
} else if (brightness < 0) {
brightness = 0;
}
mBrightness = brightness;
syncState();
}
public void setColor(int color) {
mColor = color;
syncState();
}
public void enableAllLEDs(boolean enable) {
mEnabledLeds = enable ? 31 : 0;
syncState();
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Manager;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import net.typeblog.lunatic.Constants.Constants;
public final class SettingsManager {
private static final String TAG = "SpotlightSettingsManager";
private static final boolean DEBUG = true;
public static boolean enableSpotlight(Context context, boolean enable) {
return Settings.Secure.putInt(context.getContentResolver(),
Constants.SPOTLIGHT_ENABLE, enable ? 1 : 0);
}
public static boolean isSpotlightEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Constants.SPOTLIGHT_ENABLE, 1) != 0;
}
public static float getSpotlightBrightness(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getInt(Constants.SPOTLIGHT_BRIGHTNESS, 100) / 100.0f;
}
public static boolean isSpotlightChargingEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(Constants.SPOTLIGHT_CHARGING_LEVEL_ENABLE, false) && isSpotlightEnabled(context);
}
public static boolean isSpotlightCallEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(Constants.SPOTLIGHT_CALL_ENABLE, false) && isSpotlightEnabled(context);
}
public static boolean isSpotlightNotifsEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Constants.SPOTLIGHT_NOTIFS_ENABLE, 1) != 0 && isSpotlightEnabled(context);
}
public static boolean setSpotlightNotifsEnabled(Context context, boolean enable) {
return Settings.Secure.putInt(context.getContentResolver(),
Constants.SPOTLIGHT_NOTIFS_ENABLE, enable ? 1 : 0);
}
public static boolean isSpotlightNotifsAppEnabled(Context context, String app) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(app, true) && isSpotlightNotifsEnabled(context);
}
public static boolean isSpotlightFlashlightEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(Constants.SPOTLIGHT_FLASHLIGHT_ENABLE, false) && isSpotlightEnabled(context);
}
public static boolean isSpotlightMusicEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(Constants.SPOTLIGHT_MUSIC_ENABLE, false) && isSpotlightEnabled(context);
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Manager;
public final class StatusManager {
private static final String TAG = "SpotlightStatusManager";
private static final boolean DEBUG = true;
private static boolean allLedActive = false;
private static boolean callLedActive = false;
private static boolean musicLedActive = false;
private static boolean notifLedActive = false;
private static boolean chargingLedActive = false;
public static boolean isAllLedsActive() {
return allLedActive;
}
public static void setAllLedsActive(boolean status) {
allLedActive = status;
}
public static boolean isCallLedsActive() {
return callLedActive;
}
public static void setCallLedsActive(boolean status) {
callLedActive = status;
}
public static boolean isMusicLedsActive() {
return musicLedActive;
}
public static void setMusicLedsActive(boolean status) {
musicLedActive = status;
}
public static boolean isNotifLedsActive() {
return notifLedActive;
}
public static void setNotifLedsActive(boolean status) {
notifLedActive = status;
}
public static boolean isChargingLedsActive() {
return chargingLedActive;
}
public static void setChargingLedsActive(boolean status) {
chargingLedActive = status;
}
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Services;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.util.Log;
import net.typeblog.lunatic.Manager.AnimationManager;
public class CallReceiverService extends Service {
private static final String TAG = "SpotlightCallReceiverService";
private static final boolean DEBUG = true;
private AnimationManager mAnimationManager;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mAnimationManager = new AnimationManager(this);
IntentFilter callReceiver = new IntentFilter();
callReceiver.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
registerReceiver(mCallReceiver, callReceiver);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
this.unregisterReceiver(mCallReceiver);
disableCallAnimation();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void enableCallAnimation() {
if (DEBUG) Log.d(TAG, "enableCallAnimation");
mAnimationManager.playCall();
}
private void disableCallAnimation() {
if (DEBUG) Log.d(TAG, "disableCallAnimation");
mAnimationManager.stopCall();
}
private BroadcastReceiver mCallReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
if (DEBUG) Log.d(TAG, "EXTRA_STATE_RINGING");
enableCallAnimation();
}
if ((state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))){
if (DEBUG) Log.d(TAG, "EXTRA_STATE_OFFHOOK");
disableCallAnimation();
}
if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
if (DEBUG) Log.d(TAG, "EXTRA_STATE_IDLE");
disableCallAnimation();
}
}
}
};
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2018 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Services;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import net.typeblog.lunatic.Manager.AnimationManager;
public class ChargingService extends Service {
private static final String TAG = "SpotlightChargingService";
private static final boolean DEBUG = true;
private AnimationManager mAnimationManager;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mAnimationManager = new AnimationManager(this);
IntentFilter powerMonitor = new IntentFilter();
powerMonitor.addAction(Intent.ACTION_POWER_CONNECTED);
powerMonitor.addAction(Intent.ACTION_POWER_DISCONNECTED);
registerReceiver(mPowerMonitor, powerMonitor);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
onPowerDisconnected();
super.onDestroy();
this.unregisterReceiver(mPowerMonitor);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void onPowerConnected() {
if (DEBUG) Log.d(TAG, "Power connected");
mAnimationManager.playCharging();
}
private void onPowerDisconnected() {
if (DEBUG) Log.d(TAG, "Power disconnected");
mAnimationManager.stopCharging();
}
private BroadcastReceiver mPowerMonitor = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
onPowerConnected();
} else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
onPowerDisconnected();
}
}
};
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2018 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Services;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.os.IBinder;
import android.util.Log;
import net.typeblog.lunatic.Manager.AnimationManager;
public class FlashlightService extends Service {
private static final String TAG = "SpotlightFlashlightService";
private static final boolean DEBUG = true;
private AnimationManager mAnimationManager;
private CameraManager mCameraManager;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mAnimationManager = new AnimationManager(this);
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
mCameraManager.registerTorchCallback(mTorchCallback, null);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
onTorchDisabled();
mCameraManager.unregisterTorchCallback(mTorchCallback);
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private final CameraManager.TorchCallback mTorchCallback = new CameraManager.TorchCallback() {
@Override
public void onTorchModeUnavailable(String cameraId) {
onTorchDisabled();
}
@Override
public void onTorchModeChanged(String cameraId, boolean enabled) {
if (enabled) {
onTorchEnabled();
} else {
onTorchDisabled();
}
}
};
private void onTorchEnabled() {
if (DEBUG) Log.d(TAG, "Flashlight enabled");
mAnimationManager.playFlashlight();
}
private void onTorchDisabled() {
if (DEBUG) Log.d(TAG, "Flashlight disabled");
mAnimationManager.stopFlashlight();
}
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2018 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Services;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
import android.os.IBinder;
import android.util.Log;
import net.typeblog.lunatic.Manager.AnimationManager;
import java.util.List;
public class MusicService extends Service {
private static final String TAG = "SpotlightMusicService";
private static final boolean DEBUG = true;
private AnimationManager mAnimationManager;
private AudioManager mAudioManager;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mAnimationManager = new AnimationManager(this);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mAudioManager.registerAudioPlaybackCallback(mAudioPlaybackCallback, null);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
onMusicStopped();
super.onDestroy();
mAudioManager.unregisterAudioPlaybackCallback(mAudioPlaybackCallback);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
AudioManager.AudioPlaybackCallback mAudioPlaybackCallback = new AudioManager.AudioPlaybackCallback() {
@Override
public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
if (DEBUG) Log.d(TAG, "onPlaybackConfigChanged");
if (mAudioManager.isMusicActive()) {
onMusicPlaying();
} else {
onMusicStopped();
}
super.onPlaybackConfigChanged(configs);
}
};
private void onMusicPlaying() {
if (DEBUG) Log.d(TAG, "Playing music");
mAnimationManager.playMusic();
}
private void onMusicStopped() {
if (DEBUG) Log.d(TAG, "Not playing music");
mAnimationManager.stopMusic();
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Services;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
//import com.android.internal.util.ArrayUtils;
import net.typeblog.lunatic.Constants.Constants;
import net.typeblog.lunatic.Manager.AnimationManager;
import net.typeblog.lunatic.Manager.SettingsManager;
import java.util.ArrayList;
import java.util.Arrays;
public class NotificationService extends NotificationListenerService {
private static final String TAG = "SpotlightNotification";
private static final boolean DEBUG = true;
private ArrayList<Integer> mNotifications = new ArrayList<>();
private AnimationManager mAnimationManager;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mAnimationManager = new AnimationManager(this);
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
@Override
public void onNotificationPosted(StatusBarNotification sbn){
String packageName = sbn.getPackageName();
String packageChannelID = sbn.getNotification().getChannelId();
int packageImportance = -1;
try {
Context packageContext = createPackageContext(packageName, 0);
NotificationManager packageNotificationManager = (NotificationManager) packageContext.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel packageChannel = packageNotificationManager.getNotificationChannel(packageChannelID);
if (packageChannel != null) {
packageImportance = packageChannel.getImportance();
}
} catch (PackageManager.NameNotFoundException e) {};
if (DEBUG) Log.d(TAG, "onNotificationPosted: package:" + packageName + " | channel id: " + packageChannelID + " | importance: " + packageImportance);
if (SettingsManager.isSpotlightNotifsAppEnabled(this, packageName)
&& !sbn.isOngoing()
&& !Arrays.asList(Constants.APPSTOIGNORE).contains(packageName)
&& !Arrays.asList(Constants.NOTIFSTOIGNORE).contains(packageName + ":" + packageChannelID)
&& (packageImportance >= NotificationManager.IMPORTANCE_DEFAULT || packageImportance == -1)) {
mNotifications.add(sbn.getId());
mAnimationManager.playNotifications();
}
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn){
if (DEBUG) Log.d(TAG, "onNotificationRemoved: package:" + sbn.getPackageName() + " | channel id: " + sbn.getNotification().getChannelId() + " | id: " + sbn.getId());
if (mNotifications.contains(sbn.getId())) {
mNotifications.remove((Integer) sbn.getId());
}
if (mNotifications.isEmpty()) {
mAnimationManager.stopNotifications();
}
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Settings;
import android.app.Fragment;
import android.os.Bundle;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
import com.android.settingslib.R;
public class NotifsSettingsActivity extends CollapsingToolbarBaseActivity {
private NotifsSettingsFragment mNotifsSettingsFragment;
private static final String TAG_SPOTLIGHT = "spotlightnotifs";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fragment fragment = getFragmentManager().findFragmentById(R.id.content_frame);
if (fragment == null) {
mNotifsSettingsFragment = new NotifsSettingsFragment();
getFragmentManager().beginTransaction()
.add(R.id.content_frame, mNotifsSettingsFragment, TAG_SPOTLIGHT)
.commit();
} else {
mNotifsSettingsFragment = (NotifsSettingsFragment) fragment;
}
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Settings;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Switch;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settingslib.widget.MainSwitchPreference;
import com.android.settingslib.widget.OnMainSwitchChangeListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.typeblog.lunatic.R;
import net.typeblog.lunatic.Constants.Constants;
import net.typeblog.lunatic.Manager.SettingsManager;
import net.typeblog.lunatic.Utils.ServiceUtils;
public class NotifsSettingsFragment extends PreferenceFragment implements OnPreferenceChangeListener,
OnMainSwitchChangeListener {
private PreferenceScreen mScreen;
private MainSwitchPreference mSwitchBar;
private PreferenceCategory mCategory;
private List<ApplicationInfo> mApps;
private PackageManager mPackageManager;
private Handler mHandler = new Handler();
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.spotlight_notifs_settings);
mScreen = this.getPreferenceScreen();
getActivity().setTitle(R.string.spotlight_settings_notifs_toggle_title);
mSwitchBar = (MainSwitchPreference) findPreference(Constants.SPOTLIGHT_NOTIFS_SUB_ENABLE);
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchBar.setChecked(SettingsManager.isSpotlightNotifsEnabled(getActivity()));
mCategory = (PreferenceCategory) findPreference(Constants.SPOTLIGHT_NOTIFS_SUB_CATEGORY);
mPackageManager = getActivity().getPackageManager();
mApps = mPackageManager.getInstalledApplications(PackageManager.GET_GIDS);
Collections.sort(mApps, new ApplicationInfo.DisplayNameComparator(mPackageManager));
for (ApplicationInfo app : mApps) {
if(mPackageManager.getLaunchIntentForPackage(app.packageName) != null && !Arrays.asList(Constants.APPSTOIGNORE).contains(app.packageName)) { // apps with launcher intent
SwitchPreference mSwitchPreference = new SwitchPreference(mScreen.getContext());
mSwitchPreference.setKey(app.packageName);
mSwitchPreference.setTitle(" " + app.loadLabel(mPackageManager).toString()); // add this space since the layout looks off otherwise
mSwitchPreference.setIcon(app.loadIcon(mPackageManager));
mSwitchPreference.setDefaultValue(true);
mSwitchPreference.setOnPreferenceChangeListener(this);
mCategory.addPreference(mSwitchPreference);
}
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//mHandler.post(() -> ServiceUtils.checkSpotlightService(getActivity()));
return true;
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
SettingsManager.setSpotlightNotifsEnabled(getActivity(), isChecked);
ServiceUtils.checkSpotlightService(getActivity());
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2015-2016 The CyanogenMod Project
* 2017 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Settings;
import android.app.Fragment;
import android.os.Bundle;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
import com.android.settingslib.R;
public class SettingsActivity extends CollapsingToolbarBaseActivity {
private SettingsFragment mSettingsFragment;
private static final String TAG_SPOTLIGHT = "spotlight";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fragment fragment = getFragmentManager().findFragmentById(R.id.content_frame);
if (fragment == null) {
mSettingsFragment = new SettingsFragment();
getFragmentManager().beginTransaction()
.add(R.id.content_frame, mSettingsFragment, TAG_SPOTLIGHT)
.commit();
} else {
mSettingsFragment = (SettingsFragment) fragment;
}
}
}

View file

@ -0,0 +1,163 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2019 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Settings;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.widget.Switch;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceFragment;
import androidx.preference.SeekBarPreference;
import androidx.preference.SwitchPreference;
import com.android.settingslib.widget.MainSwitchPreference;
import com.android.settingslib.widget.OnMainSwitchChangeListener;
import net.typeblog.lunatic.R;
import net.typeblog.lunatic.Constants.Constants;
import net.typeblog.lunatic.Manager.SettingsManager;
import net.typeblog.lunatic.Utils.ServiceUtils;
public class SettingsFragment extends PreferenceFragment implements OnPreferenceChangeListener,
OnMainSwitchChangeListener {
private MainSwitchPreference mSwitchBar;
private SeekBarPreference mBrightnessPreference;
private SwitchPreference mNotifsPreference;
private SwitchPreference mCallPreference;
private SwitchPreference mChargingLevelPreference;
private SwitchPreference mFlashlightPreference;
private SwitchPreference mMusicPreference;
private ContentResolver mContentResolver;
private SettingObserver mSettingObserver;
private Handler mHandler = new Handler();
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.spotlight_settings);
mContentResolver = getActivity().getContentResolver();
mSettingObserver = new SettingObserver();
mSettingObserver.register(mContentResolver);
boolean spotlightEnabled = SettingsManager.isSpotlightEnabled(getActivity());
mSwitchBar = (MainSwitchPreference) findPreference(Constants.SPOTLIGHT_ENABLE);
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchBar.setChecked(spotlightEnabled);
mBrightnessPreference = (SeekBarPreference) findPreference(Constants.SPOTLIGHT_BRIGHTNESS);
mBrightnessPreference.setEnabled(spotlightEnabled);
mBrightnessPreference.setMin(1);
mBrightnessPreference.setMax(100);
mBrightnessPreference.setUpdatesContinuously(true);
mBrightnessPreference.setOnPreferenceChangeListener(this);
mNotifsPreference = (SwitchPreference) findPreference(Constants.SPOTLIGHT_NOTIFS_ENABLE);
mNotifsPreference.setChecked(SettingsManager.isSpotlightNotifsEnabled(getActivity()));
mNotifsPreference.setEnabled(spotlightEnabled);
mNotifsPreference.setOnPreferenceChangeListener(this);
mCallPreference = (SwitchPreference) findPreference(Constants.SPOTLIGHT_CALL_ENABLE);
mCallPreference.setEnabled(spotlightEnabled);
mCallPreference.setOnPreferenceChangeListener(this);
mChargingLevelPreference = (SwitchPreference) findPreference(Constants.SPOTLIGHT_CHARGING_LEVEL_ENABLE);
mChargingLevelPreference.setEnabled(spotlightEnabled);
mChargingLevelPreference.setOnPreferenceChangeListener(this);
mFlashlightPreference = (SwitchPreference) findPreference(Constants.SPOTLIGHT_FLASHLIGHT_ENABLE);
mFlashlightPreference.setEnabled(spotlightEnabled);
mFlashlightPreference.setOnPreferenceChangeListener(this);
mMusicPreference = (SwitchPreference) findPreference(Constants.SPOTLIGHT_MUSIC_ENABLE);
mMusicPreference.setEnabled(spotlightEnabled);
mMusicPreference.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final String preferenceKey = preference.getKey();
if (preferenceKey.equals(Constants.SPOTLIGHT_NOTIFS_ENABLE)) {
SettingsManager.setSpotlightNotifsEnabled(getActivity(), true);
}
if (preferenceKey.equals(Constants.SPOTLIGHT_BRIGHTNESS)) {
Constants.setBrightness(((int) newValue) / 100.0f);
} else {
mHandler.post(() -> ServiceUtils.checkSpotlightService(getActivity()));
}
return true;
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
SettingsManager.enableSpotlight(getActivity(), isChecked);
ServiceUtils.checkSpotlightService(getActivity());
mSwitchBar.setChecked(isChecked);
mBrightnessPreference.setEnabled(isChecked);
mNotifsPreference.setEnabled(isChecked);
mCallPreference.setEnabled(isChecked);
mChargingLevelPreference.setEnabled(isChecked);
mFlashlightPreference.setEnabled(isChecked);
mMusicPreference.setEnabled(isChecked);
}
@Override
public void onDestroy() {
mSettingObserver.unregister(mContentResolver);
super.onDestroy();
}
private class SettingObserver extends ContentObserver {
public SettingObserver() {
super(new Handler());
}
public void register(ContentResolver cr) {
cr.registerContentObserver(Settings.Secure.getUriFor(
Constants.SPOTLIGHT_NOTIFS_ENABLE), false, this);
}
public void unregister(ContentResolver cr) {
cr.unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (uri.equals(Settings.Secure.getUriFor(Constants.SPOTLIGHT_NOTIFS_ENABLE))) {
mNotifsPreference.setChecked(SettingsManager.isSpotlightNotifsEnabled(getActivity()));
}
}
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2019 The LineageOS Project
* 2020-2022 Paranoid Android
*
* 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 net.typeblog.lunatic.Utils;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import net.typeblog.lunatic.Constants.Constants;
import net.typeblog.lunatic.Manager.AnimationManager;
import net.typeblog.lunatic.Manager.SettingsManager;
import net.typeblog.lunatic.Services.CallReceiverService;
import net.typeblog.lunatic.Services.ChargingService;
import net.typeblog.lunatic.Services.FlashlightService;
import net.typeblog.lunatic.Services.MusicService;
import net.typeblog.lunatic.Services.NotificationService;
public final class ServiceUtils {
private static final String TAG = "SpotlightServiceUtils";
private static final boolean DEBUG = true;
public static void startCallReceiverService(Context context) {
if (DEBUG) Log.d(TAG, "Starting Spotlight call receiver service");
context.startService(new Intent(context, CallReceiverService.class));
}
protected static void stopCallReceiverService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping Spotlight call receiver service");
context.stopService(new Intent(context, CallReceiverService.class));
}
public static void startChargingService(Context context) {
if (DEBUG) Log.d(TAG, "Starting Spotlight charging service");
context.startService(new Intent(context, ChargingService.class));
}
protected static void stopChargingService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping Spotlight charging service");
context.stopService(new Intent(context, ChargingService.class));
}
public static void startNotificationService(Context context) {
if (DEBUG) Log.d(TAG, "Starting Spotlight notifs service");
context.startService(new Intent(context, NotificationService.class));
}
protected static void stopNotificationService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping Spotlight notifs service");
context.stopService(new Intent(context, NotificationService.class));
}
public static void startFlashlightService(Context context) {
if (DEBUG) Log.d(TAG, "Starting Spotlight flashlight service");
context.startService(new Intent(context, FlashlightService.class));
}
protected static void stopFlashlightService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping Spotlight flashlight service");
context.stopService(new Intent(context, FlashlightService.class));
}
public static void startMusicService(Context context) {
if (DEBUG) Log.d(TAG, "Starting Spotlight Music service");
context.startService(new Intent(context, MusicService.class));
}
protected static void stopMusicService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping Spotlight Music service");
context.stopService(new Intent(context, MusicService.class));
}
public static void checkSpotlightService(Context context) {
AnimationManager animationManager = new AnimationManager(context);
if (SettingsManager.isSpotlightEnabled(context)) {
Constants.setBrightness(SettingsManager.getSpotlightBrightness(context));
if (SettingsManager.isSpotlightChargingEnabled(context)) {
startChargingService(context);
} else {
stopChargingService(context);
}
if (SettingsManager.isSpotlightCallEnabled(context)) {
startCallReceiverService(context);
} else {
stopCallReceiverService(context);
}
if (SettingsManager.isSpotlightNotifsEnabled(context)) {
startNotificationService(context);
} else {
stopNotificationService(context);
}
if (SettingsManager.isSpotlightFlashlightEnabled(context)) {
startFlashlightService(context);
} else {
stopFlashlightService(context);
}
if (SettingsManager.isSpotlightMusicEnabled(context)) {
startMusicService(context);
} else {
stopMusicService(context);
}
} else {
stopChargingService(context);
stopCallReceiverService(context);
stopNotificationService(context);
stopFlashlightService(context);
stopMusicService(context);
}
}
}