├── example.keystore.jks ├── ic_launcher-web.png ├── proguard-project.txt ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ ├── res │ │ ├── drawable-hdpi │ │ │ ├── ic_add.png │ │ │ ├── ic_delete.png │ │ │ ├── ic_help.png │ │ │ ├── ic_wifi.png │ │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ │ ├── ic_add.png │ │ │ ├── ic_delete.png │ │ │ ├── ic_help.png │ │ │ ├── ic_wifi.png │ │ │ └── ic_launcher.png │ │ ├── drawable │ │ │ ├── icon_black.png │ │ │ ├── event_wifi_on.xml │ │ │ ├── event_app_enabled.xml │ │ │ ├── event_display_on.xml │ │ │ ├── event_wifi_disconnected.xml │ │ │ ├── event_ac_connected.xml │ │ │ ├── event_error.xml │ │ │ ├── event_display_off.xml │ │ │ ├── event_location_entered.xml │ │ │ ├── event_timer.xml │ │ │ ├── event_wifi_off.xml │ │ │ ├── event_airplane_mode.xml │ │ │ ├── event_app_disabled.xml │ │ │ ├── event_unlock.xml │ │ │ ├── event_ac_disconnected.xml │ │ │ └── event_hotspot.xml │ │ ├── drawable-xhdpi │ │ │ ├── ic_add.png │ │ │ ├── ic_help.png │ │ │ ├── ic_wifi.png │ │ │ ├── ic_delete.png │ │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ │ ├── ic_add.png │ │ │ ├── ic_help.png │ │ │ ├── ic_wifi.png │ │ │ ├── ic_delete.png │ │ │ └── ic_launcher.png │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── styles.xml │ │ │ └── strings.xml │ │ ├── values-v21 │ │ │ └── styles.xml │ │ ├── layout │ │ │ ├── logitem.xml │ │ │ └── statepreference.xml │ │ ├── xml │ │ │ └── preferences.xml │ │ ├── xml-v26 │ │ │ └── preferences.xml │ │ ├── values-pl │ │ │ └── strings.xml │ │ ├── values-cs │ │ │ └── strings.xml │ │ ├── values-fr │ │ │ └── strings.xml │ │ ├── values-it │ │ │ └── strings.xml │ │ ├── values-pt │ │ │ └── strings.xml │ │ ├── values-ru │ │ │ └── strings.xml │ │ ├── values-es │ │ │ └── strings.xml │ │ └── values-de │ │ │ └── strings.xml │ ├── java │ │ └── de │ │ │ └── j4velin │ │ │ └── wifiAutoOff │ │ │ ├── NoticePreference.java │ │ │ ├── Util.java │ │ │ ├── APILevel14Wrapper.java │ │ │ ├── APILevel19Wrapper.java │ │ │ ├── LogDeleteService.java │ │ │ ├── APILevel23Wrapper.java │ │ │ ├── APILevel24Wrapper.java │ │ │ ├── APILevel20Wrapper.java │ │ │ ├── QSTileService.java │ │ │ ├── APILevel17Wrapper.java │ │ │ ├── UnlockReceiver.java │ │ │ ├── APILevel11Wrapper.java │ │ │ ├── LogAdapter.java │ │ │ ├── StartReceiver.java │ │ │ ├── Logger.java │ │ │ ├── ScreenChangeDetector.java │ │ │ ├── StatusPreference.java │ │ │ ├── APILevel26ForegroundService.java │ │ │ ├── Log.java │ │ │ ├── Start.java │ │ │ └── Receiver.java │ └── AndroidManifest.xml ├── play │ ├── res │ │ ├── layout │ │ │ ├── map.xml │ │ │ ├── location.xml │ │ │ └── locations.xml │ │ ├── menu │ │ │ └── menu.xml │ │ └── raw │ │ │ └── map.json │ ├── java │ │ └── de │ │ │ └── j4velin │ │ │ └── wifiAutoOff │ │ │ ├── Location.java │ │ │ ├── GeoFenceService.java │ │ │ ├── Map.java │ │ │ ├── GeofenceUpdateService.java │ │ │ └── Database.java │ ├── AndroidManifest.xml │ └── aidl │ │ └── com │ │ └── android │ │ └── vending │ │ └── billing │ │ └── IInAppBillingService.aidl └── fdroid │ ├── java │ └── de │ │ └── j4velin │ │ └── wifiAutoOff │ │ ├── Locations.java │ │ ├── GeoFenceService.java │ │ └── GeofenceUpdateService.java │ └── res │ └── menu │ └── menu.xml ├── NOTICE ├── key.properties.sample ├── .travis.yml ├── .gitignore ├── README.md ├── gradlew.bat ├── gradlew └── LICENSE.md /example.keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/example.keystore.jks -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/ic_launcher-web.png -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | -renamesourcefileattribute SourceFile 2 | -keepattributes SourceFile,LineNumberTable -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/res/drawable-hdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-hdpi/ic_add.png -------------------------------------------------------------------------------- /src/main/res/drawable-mdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-mdpi/ic_add.png -------------------------------------------------------------------------------- /src/main/res/drawable/icon_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable/icon_black.png -------------------------------------------------------------------------------- /src/main/res/drawable-hdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-hdpi/ic_delete.png -------------------------------------------------------------------------------- /src/main/res/drawable-hdpi/ic_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-hdpi/ic_help.png -------------------------------------------------------------------------------- /src/main/res/drawable-hdpi/ic_wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-hdpi/ic_wifi.png -------------------------------------------------------------------------------- /src/main/res/drawable-mdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-mdpi/ic_delete.png -------------------------------------------------------------------------------- /src/main/res/drawable-mdpi/ic_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-mdpi/ic_help.png -------------------------------------------------------------------------------- /src/main/res/drawable-mdpi/ic_wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-mdpi/ic_wifi.png -------------------------------------------------------------------------------- /src/main/res/drawable-xhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xhdpi/ic_add.png -------------------------------------------------------------------------------- /src/main/res/drawable-xhdpi/ic_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xhdpi/ic_help.png -------------------------------------------------------------------------------- /src/main/res/drawable-xhdpi/ic_wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xhdpi/ic_wifi.png -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xxhdpi/ic_add.png -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/ic_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xxhdpi/ic_help.png -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/ic_wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xxhdpi/ic_wifi.png -------------------------------------------------------------------------------- /src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable-xhdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xhdpi/ic_delete.png -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xxhdpi/ic_delete.png -------------------------------------------------------------------------------- /src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j4velin/WiFi-Automatic/HEAD/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #33b5e5 4 | #33b5e5 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | WiFi-Automatic 2 | Copyright 2013-2017 Thomas Hoffmann 3 | 4 | This product includes software developed at j4velin development (http://j4velin.de) by Thomas Hoffmann (http://hoffmann-thomas.de) 5 | -------------------------------------------------------------------------------- /src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /key.properties.sample: -------------------------------------------------------------------------------- 1 | # Add your keystore credentials here and rename the file to 'key.properties' 2 | 3 | keyStore=example.keystore.jks 4 | 5 | keyStorePassword=android 6 | 7 | keyAlias=android 8 | 9 | keyAliasPassword=android 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Aug 02 09:58:51 CEST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | jdk: 4 | - oraclejdk8 5 | 6 | android: 7 | components: 8 | - platform-tools 9 | - tools 10 | - build-tools-29.0.2 11 | - android-29 12 | - extra-google-google_play_services 13 | - extra-google-m2repository 14 | - extra-android-m2repository 15 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_wifi_on.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_app_enabled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_display_on.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/play/res/layout/map.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_wifi_disconnected.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_ac_connected.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_error.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_display_off.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_location_entered.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_timer.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_wifi_off.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_airplane_mode.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | key.properties 18 | keys.xml 19 | 20 | # Windows thumbnail db 21 | Thumbs.db 22 | 23 | # OSX files 24 | .DS_Store 25 | 26 | # Eclipse project files 27 | .classpath 28 | .project 29 | 30 | # Android Studio 31 | .idea 32 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. 33 | .gradle 34 | build/ 35 | *.iml -------------------------------------------------------------------------------- /src/main/res/drawable/event_app_disabled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_unlock.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_ac_disconnected.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/NoticePreference.java: -------------------------------------------------------------------------------- 1 | package de.j4velin.wifiAutoOff; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.preference.Preference; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | public class NoticePreference extends Preference { 11 | 12 | public NoticePreference(final Context context, final AttributeSet attrs) { 13 | super(context, attrs); 14 | } 15 | 16 | @Override 17 | protected View onCreateView(final ViewGroup parent) { 18 | View v = super.onCreateView(parent); 19 | v.setBackgroundColor(Color.parseColor("#66ccff")); 20 | return v; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/res/drawable/event_hotspot.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/Util.java: -------------------------------------------------------------------------------- 1 | package de.j4velin.wifiAutoOff; 2 | 3 | import android.app.AlarmManager; 4 | import android.app.PendingIntent; 5 | import android.content.Context; 6 | import android.os.Build; 7 | 8 | public final class Util { 9 | private Util() { 10 | } 11 | 12 | public static void setTimer(final Context context, int type, long time, PendingIntent intent) { 13 | AlarmManager am = ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)); 14 | if (Build.VERSION.SDK_INT >= 23) { 15 | APILevel23Wrapper.setAlarmWhileIdle(am, type, time, intent); 16 | } else if (Build.VERSION.SDK_INT >= 19) { 17 | APILevel19Wrapper.setExactTimer(am, type, time, intent); 18 | } else { 19 | am.set(type, time, intent); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/res/layout/logitem.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 16 | -------------------------------------------------------------------------------- /src/fdroid/java/de/j4velin/wifiAutoOff/Locations.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | /** 19 | * Dummy class, "play" build flavor contains actual implementation 20 | */ 21 | public class Locations { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/fdroid/java/de/j4velin/wifiAutoOff/GeoFenceService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | /** 19 | * Dummy class, "play" build flavor contains actual implementation 20 | */ 21 | public class GeoFenceService { 22 | public final static String LOCATION_ENTERED_ACTION = "LOCATION_ENTERED"; 23 | } 24 | -------------------------------------------------------------------------------- /src/fdroid/res/menu/menu.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 15 | 20 | 25 | 26 | -------------------------------------------------------------------------------- /src/play/res/menu/menu.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 15 | 20 | 26 | 27 | -------------------------------------------------------------------------------- /src/play/java/de/j4velin/wifiAutoOff/Location.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import com.google.android.gms.maps.model.LatLng; 19 | 20 | class Location { 21 | final LatLng coords; 22 | final String name; 23 | 24 | public Location(final String name, final LatLng latlon) { 25 | this.coords = latlon; 26 | this.name = name; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel14Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.annotation.TargetApi; 19 | import android.net.wifi.p2p.WifiP2pInfo; 20 | import android.os.Build; 21 | 22 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 23 | public class APILevel14Wrapper { 24 | public static boolean groupFormed(final WifiP2pInfo info) { 25 | return info.groupFormed; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel19Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.annotation.TargetApi; 19 | import android.app.AlarmManager; 20 | import android.app.PendingIntent; 21 | 22 | @TargetApi(19) 23 | abstract class APILevel19Wrapper { 24 | static void setExactTimer(final AlarmManager am, int type, long time, PendingIntent pi) { 25 | am.setExact(type, time, pi); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/LogDeleteService.java: -------------------------------------------------------------------------------- 1 | package de.j4velin.wifiAutoOff; 2 | 3 | import android.app.AlarmManager; 4 | import android.app.PendingIntent; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.support.annotation.NonNull; 8 | import android.support.v4.app.JobIntentService; 9 | 10 | /** 11 | * Service to call {@link Log#deleteOldLogs(Context, long)} every {@link Log#KEEP_DURATION} ms 12 | */ 13 | public class LogDeleteService extends JobIntentService { 14 | 15 | private static final int JOB_ID = 42; 16 | 17 | public static void enqueueJob(Context context) { 18 | enqueueWork(context, LogDeleteService.class, JOB_ID, new Intent()); 19 | } 20 | 21 | @Override 22 | protected void onHandleWork(@NonNull Intent intent) { 23 | Log.deleteOldLogs(this, Log.KEEP_DURATION); 24 | ((AlarmManager) getSystemService(Context.ALARM_SERVICE)) 25 | .set(AlarmManager.RTC, System.currentTimeMillis() + Log.KEEP_DURATION, PendingIntent 26 | .getService(this, 0, new Intent(this, LogDeleteService.class), 27 | PendingIntent.FLAG_UPDATE_CURRENT)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel23Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.annotation.TargetApi; 20 | import android.app.AlarmManager; 21 | import android.app.PendingIntent; 22 | import android.os.Build; 23 | 24 | @TargetApi(Build.VERSION_CODES.M) 25 | public class APILevel23Wrapper { 26 | 27 | public static void setAlarmWhileIdle(AlarmManager am, int type, long time, 28 | PendingIntent intent) { 29 | am.setAndAllowWhileIdle(type, time, intent); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel24Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.ComponentName; 21 | import android.content.Context; 22 | import android.os.Build; 23 | import android.service.quicksettings.TileService; 24 | 25 | @TargetApi(Build.VERSION_CODES.N) 26 | public class APILevel24Wrapper { 27 | 28 | public static void updateTile(final Context context) { 29 | TileService.requestListeningState(context, new ComponentName(context, QSTileService.class)); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/fdroid/java/de/j4velin/wifiAutoOff/GeofenceUpdateService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.support.annotation.NonNull; 21 | import android.support.v4.app.JobIntentService; 22 | 23 | /** 24 | * Dummy class, "play" build flavor contains actual implementation 25 | */ 26 | public class GeofenceUpdateService extends JobIntentService { 27 | 28 | public static void enqueueJob(Context context) { 29 | } 30 | 31 | @Override 32 | protected void onHandleWork(@NonNull Intent intent) { 33 | stopSelf(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel20Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.hardware.display.DisplayManager; 21 | import android.view.Display; 22 | 23 | @TargetApi(20) 24 | abstract class APILevel20Wrapper { 25 | static boolean isScreenOn(final Context context) { 26 | DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 27 | for (Display display : dm.getDisplays()) { 28 | if (display.getState() != Display.STATE_OFF) { 29 | return true; 30 | } 31 | } 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/QSTileService.java: -------------------------------------------------------------------------------- 1 | package de.j4velin.wifiAutoOff; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.ComponentName; 5 | import android.content.pm.PackageManager; 6 | import android.os.Build; 7 | import android.service.quicksettings.Tile; 8 | import android.service.quicksettings.TileService; 9 | 10 | @TargetApi(Build.VERSION_CODES.N) 11 | public class QSTileService extends TileService { 12 | @Override 13 | public void onClick() { 14 | if (BuildConfig.DEBUG) Logger.log("QSTile click -> change enable state"); 15 | boolean isEnabled = getPackageManager().getComponentEnabledSetting( 16 | new ComponentName(QSTileService.this, Receiver.class)) != 17 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 18 | Preferences.changeEnableState(getApplicationContext(), !isEnabled); 19 | } 20 | 21 | @Override 22 | public void onStartListening() { 23 | super.onStartListening(); 24 | boolean isEnabled = getPackageManager().getComponentEnabledSetting( 25 | new ComponentName(QSTileService.this, Receiver.class)) != 26 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 27 | Tile tile = getQsTile(); 28 | tile.setState(isEnabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); 29 | tile.updateTile(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel17Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.provider.Settings; 22 | import android.provider.Settings.SettingNotFoundException; 23 | 24 | @TargetApi(17) 25 | abstract class APILevel17Wrapper { 26 | 27 | static boolean sleepPolicySetToNever(final Context c) throws SettingNotFoundException { 28 | return Settings.Global.WIFI_SLEEP_POLICY_NEVER == Settings.Global.getInt(c.getContentResolver(), 29 | Settings.Global.WIFI_SLEEP_POLICY); 30 | } 31 | 32 | static boolean isAirplaneModeOn(final Context c) throws SettingNotFoundException { 33 | return Settings.Global.getInt(c.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON) == 1; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WiFi Automatic 2 | ============= 3 | 4 | [![Build Status](https://travis-ci.org/j4velin/WiFi-Automatic.svg?branch=master)](https://travis-ci.org/j4velin/WiFi-Automatic) 5 | 6 | This simple app can help you increase the standby time of your device: WiFi Automatic automatically disable your WiFi radio when you don't need it and thereby lowers the battery consumption. 7 | It is designed to be used with WiFi-only* tablets - these devices normally don't require a constant internet connection if you're not using them and turning WiFi off can save a lot of battery power. 8 | 9 | You can also specify to automatically turn on WiFi again, if you turn on your device. Also, the app can regularly scan for available networks to connect to and re-disable WiFi if no suitable network is found. This way, you are always connected to your WiFi network when using the device. 10 | 11 | This app has a similiar effect like setting the "WiFi sleep policy" in Android to "always", except that you can now exactly define the timeout between turning the screen off and actually turning off WiFi. 12 | 13 | 14 | *if your device has a cell radio, it might switch to 2G/3G which may consume more power then staying on WiFi 15 | 16 | 17 | 18 | 19 | You can download the app for free from the Play Store or from F-Droid 20 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/UnlockReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.content.BroadcastReceiver; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | 23 | /** 24 | * Class for receiving the USER_PRESENT event. Can be disabled if that option is not required 25 | */ 26 | public class UnlockReceiver extends BroadcastReceiver { 27 | 28 | public final static String USER_PRESENT_ACTION = "USER_PRESENT"; 29 | 30 | @Override 31 | public void onReceive(final Context context, final Intent intent) { 32 | final String action = intent.getAction(); 33 | if (Intent.ACTION_USER_PRESENT.equals(action)) { 34 | context.sendBroadcast( 35 | new Intent(context, Receiver.class).setAction(USER_PRESENT_ACTION)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/res/layout/statepreference.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 24 | 25 | 33 | 34 | 42 | -------------------------------------------------------------------------------- /src/play/res/layout/location.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 27 | 28 | 39 | 40 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/main/res/xml/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 11 | 14 | 17 | 22 | 26 | 27 | 28 | 32 | 36 | 39 | 40 | 41 | 46 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/main/res/xml-v26/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 12 | 13 | 14 | 18 | 21 | 24 | 29 | 33 | 34 | 35 | 39 | 43 | 46 | 47 | 48 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel11Wrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.annotation.TargetApi; 20 | import android.app.AlertDialog; 21 | import android.content.Context; 22 | import android.content.DialogInterface; 23 | import android.content.DialogInterface.OnClickListener; 24 | import android.content.SharedPreferences; 25 | import android.os.Build; 26 | import android.preference.Preference; 27 | import android.widget.NumberPicker; 28 | 29 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 30 | abstract class APILevel11Wrapper { 31 | 32 | static void showNumberPicker(final Context c, final SharedPreferences prefs, final Preference p, final int summary, final int min, final int max, final String title, final String setting, final int def, final boolean changeTitle) { 33 | if (c == null) return; 34 | final NumberPicker np = new NumberPicker(c); 35 | np.setMinValue(min); 36 | np.setMaxValue(max); 37 | np.setValue(prefs.getInt(setting, def)); 38 | new AlertDialog.Builder(c).setTitle(title).setView(np) 39 | .setPositiveButton(android.R.string.ok, new OnClickListener() { 40 | @Override 41 | public void onClick(DialogInterface dialog, int which) { 42 | np.clearFocus(); 43 | prefs.edit().putInt(setting, np.getValue()).apply(); 44 | if (changeTitle) p.setTitle(c.getString(summary, np.getValue())); 45 | else p.setSummary(c.getString(summary, np.getValue())); 46 | } 47 | }).create().show(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/play/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 31 | 32 | 35 | 38 | 39 | 42 | 45 | 46 | 50 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/LogAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.support.v7.widget.RecyclerView; 19 | import android.view.LayoutInflater; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.widget.TextView; 23 | 24 | import java.text.DateFormat; 25 | import java.text.SimpleDateFormat; 26 | import java.util.Date; 27 | import java.util.List; 28 | 29 | public class LogAdapter extends RecyclerView.Adapter { 30 | 31 | private final List items; 32 | private final static DateFormat dateFormat = SimpleDateFormat.getTimeInstance(); 33 | 34 | public LogAdapter(final List items) { 35 | this.items = items; 36 | } 37 | 38 | @Override 39 | public Holder onCreateViewHolder(final ViewGroup parent, int viewType) { 40 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.logitem, parent, false); 41 | Holder holder = new Holder(v); 42 | return holder; 43 | } 44 | 45 | @Override 46 | public void onBindViewHolder(final Holder holder, int position) { 47 | Log.Item item = items.get(position); 48 | holder.date.setText(dateFormat.format(new Date(item.date))); 49 | holder.text.setText(item.text); 50 | holder.text.setCompoundDrawablesWithIntrinsicBounds(item.type.drawable, 0, 0, 0); 51 | } 52 | 53 | @Override 54 | public int getItemCount() { 55 | return items.size(); 56 | } 57 | 58 | public class Holder extends RecyclerView.ViewHolder { 59 | 60 | private final TextView date, text; 61 | 62 | public Holder(final View itemView) { 63 | super(itemView); 64 | date = (TextView) itemView.findViewById(R.id.date); 65 | text = (TextView) itemView.findViewById(R.id.text); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/StartReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.content.BroadcastReceiver; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.IntentFilter; 23 | import android.os.BatteryManager; 24 | 25 | /** 26 | * BroadcastReceiver which receives BOOT_COMPLETE & PACKAGE_REPLACED and then 27 | * starts all necessary timers 28 | * 29 | * @see Start 30 | */ 31 | public class StartReceiver extends BroadcastReceiver { 32 | 33 | @Override 34 | public void onReceive(final Context context, final Intent intent) { 35 | if (BuildConfig.DEBUG) Logger.log("received: " + intent.getAction()); 36 | if (!Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction()) || 37 | intent.getDataString().contains(context.getPackageName())) { 38 | LogDeleteService.enqueueJob(context); 39 | } 40 | if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { 41 | // AC already connected on boot? 42 | try { 43 | Intent batteryIntent = context.registerReceiver(null, 44 | new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 45 | int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); 46 | if (plugged == BatteryManager.BATTERY_PLUGGED_AC || 47 | plugged == BatteryManager.BATTERY_PLUGGED_USB) { 48 | context.sendBroadcast( 49 | // we're not allowed to send Intent.ACTION_POWER_CONNECTED, so use our own action 50 | new Intent(context, Receiver.class) 51 | .setAction(Receiver.POWER_CONNECTED)); 52 | } 53 | } catch (Throwable t) { 54 | // ReceiverCallNotAllowedException might be thrown on Samsung devices... 55 | if (BuildConfig.DEBUG) Logger.log(t); 56 | } 57 | } 58 | Start.start(context); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/res/values-pl/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | przez co najmniej %d minut 5 | codziennie o %s 6 | co każde %s 7 | Zaawansowane ustawienia WiFi 8 | Więcej aplikacji 9 | Darowizna 10 | Uruchom włączenie WiFi… 11 | urządzenie zostanie odblokowane 12 | Uruchom wyłączenie WiFi gdy… 13 | ekran jest wyłączony 14 | nie jest podłączony do żadnej sieci 15 | Twoje ustawienia WiFi są ustawione na automatyczne wyłączenie gdy tylko wyświetlacz zgaśnie. Możesz zmienić te ustawienia w \'Zaawansowane ustawienia WiFi\' Androida 16 | Zaawansowane ustawienia WiFi 17 | Ustawień nie znaleziono! 18 | Minut przed wyłączeniem WiFi: 19 | Uruchom włączenie WiFi o: 20 | Uruchom wyłączenie WiFi o: 21 | Uruchom włączenie WiFi co … 22 | Nieprawidłowy wpis: Liczba musi być >= %1$d i <= %2$d 23 | po podłączeniu do zewnętrznego źródła zasilania 24 | 25 | 26 | 5 minut 27 | 15 minut 28 | 30 minut 29 | 1 godzine 30 | 2 godziny 31 | 5 godzin 32 | 10 godzin 33 | 34 | 35 | Ustawienia ogólne 36 | Tryb samolotowy 37 | Nie włączaj WiFi w trybie samolotowym 38 | gdy znajdziesz się w określonych miejscach 39 | Tylko jedna lokalizacja jest wspierana w darmowej wersji aplikacjii. Czy chcesz teraz uaktualnić do wersji pro?? 40 | Włącz WiFi gdy znajdziesz się w tej lokalizacji: 41 | Użyj informacji o lokalizacji komórki, aby włączyć WiFi w określonych miejscach 42 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/Logger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.database.Cursor; 20 | import android.os.Environment; 21 | 22 | import java.io.File; 23 | import java.io.FileWriter; 24 | import java.io.IOException; 25 | import java.util.Date; 26 | 27 | abstract class Logger { 28 | 29 | private static FileWriter fw; 30 | private static final Date date = new Date(); 31 | private final static String APP = "WiFi-Automatic"; 32 | 33 | public static void log(final Throwable ex) { 34 | if (!BuildConfig.DEBUG) return; 35 | log(ex.getMessage()); 36 | for (StackTraceElement ste : ex.getStackTrace()) { 37 | log(ste.toString()); 38 | } 39 | } 40 | 41 | public static void log(final Cursor c) { 42 | if (!BuildConfig.DEBUG) return; 43 | c.moveToFirst(); 44 | String title = ""; 45 | for (int i = 0; i < c.getColumnCount(); i++) 46 | title += c.getColumnName(i) + " | "; 47 | log(title); 48 | while (!c.isAfterLast()) { 49 | title = ""; 50 | for (int i = 0; i < c.getColumnCount(); i++) 51 | title += c.getString(i) + " | "; 52 | log(title); 53 | c.moveToNext(); 54 | } 55 | } 56 | 57 | @SuppressWarnings("deprecation") 58 | public static void log(String msg) { 59 | if (!BuildConfig.DEBUG) return; 60 | android.util.Log.d(APP, msg); 61 | try { 62 | if (fw == null) { 63 | fw = new FileWriter(new File( 64 | Environment.getExternalStorageDirectory().toString() + "/" + APP + ".log"), 65 | true); 66 | } 67 | date.setTime(System.currentTimeMillis()); 68 | fw.write(date.toLocaleString() + " - " + msg + "\n"); 69 | fw.flush(); 70 | } catch (IOException e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | protected void finalize() throws Throwable { 76 | try { 77 | if (fw != null) fw.close(); 78 | } finally { 79 | super.finalize(); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/res/values-cs/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | alespoň %d min 5 | každý den v %s 6 | každé %s 7 | Rozšířené WiFi nastavení 8 | Další aplikace 9 | Podpořit 10 | Zapnout WiFi… 11 | po odemčení přístroje 12 | Vypnout WiFi pokud… 13 | je vypnutý displej 14 | bez připojení k jakékoliv síti 15 | WiFi připojení je nastaveno na automatické vypnutí při vypnutí displeje. Toto nastavení lze změnit v \'Rozšířeném nastavení WiFi\' Androidu 16 | Roz. WiFi nastavení 17 | Nastavení nenalezeno! 18 | Minut před vypnutím WiFi: 19 | Zapnout WiFi v: 20 | Vypnout WiFi v: 21 | Zapnout WiFi každé … 22 | Neplatný vstup: Číslo musí být >= %1$d a <= %2$d 23 | při napájení 24 | Také ignorovat nastavení \"vypnutý displej\" při napájení 25 | 26 | 27 | 5 min 28 | 15 min 29 | 30 min 30 | 1 hodina 31 | 2 hodiny 32 | 5 hodin 33 | 10 hodin 34 | 35 | 36 | Hlavní nastavení 37 | Mód Letadlo 38 | Nezapínat WiFi v módu Letadlo 39 | při vstupu do těchto lokací 40 | Ve volné verzi této aplikaci je podporována pouze jedna lokace. Chcete nyní aktualizovat na pro verzi? 41 | Zapnout WiFi při vstupu do těchto lokací: 42 | Používat informace telefonních ústředen pro zapnutí WiFi ve specifických lokacích 43 | WiFi odpojeno 44 | Kliknout pro výběr WiFi sítě 45 | WiFi vypnuto 46 | Kliknutím zapnout 47 | Nastavení zamezuje aplikaci detekovat vaše umístění 48 | Interval: 49 | Aktivní skenování umístění 50 | Více informací 51 | Aplikace nemá oprávnění pro zjištění vašeho umístění 52 | -------------------------------------------------------------------------------- /src/play/java/de/j4velin/wifiAutoOff/GeoFenceService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.app.IntentService; 19 | import android.content.Intent; 20 | 21 | import com.google.android.gms.location.FusedLocationProviderApi; 22 | import com.google.android.gms.location.Geofence; 23 | import com.google.android.gms.location.GeofencingEvent; 24 | import com.google.android.gms.maps.model.LatLng; 25 | 26 | public class GeoFenceService extends IntentService { 27 | 28 | public GeoFenceService() { 29 | super("WiFiAutomaticGeoFenceService"); 30 | } 31 | 32 | @Override 33 | protected void onHandleIntent(final Intent intent) { 34 | if (intent == null) return; 35 | if (intent.hasExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED)) { 36 | android.location.Location loc = (android.location.Location) intent.getExtras() 37 | .get(FusedLocationProviderApi.KEY_LOCATION_CHANGED); 38 | if (BuildConfig.DEBUG) Logger.log("Location update received " + loc); 39 | Database db = Database.getInstance(this); 40 | if (db.inRangeOfLocation(loc)) { 41 | sendBroadcast(new Intent(this, Receiver.class) 42 | .setAction(Receiver.LOCATION_ENTERED_ACTION)); 43 | } 44 | db.close(); 45 | } else { 46 | GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 47 | // First check for errors 48 | if (geofencingEvent.hasError()) { 49 | // Get the error code with a static method 50 | // Log the error 51 | if (BuildConfig.DEBUG) Logger.log("Location Services error: " + 52 | Integer.toString(geofencingEvent.getErrorCode())); 53 | } else { 54 | // Test that a valid transition was reported 55 | if (geofencingEvent.getGeofenceTransition() == Geofence.GEOFENCE_TRANSITION_ENTER) { 56 | Database db = Database.getInstance(this); 57 | for (Geofence gf : geofencingEvent.getTriggeringGeofences()) { 58 | if (BuildConfig.DEBUG) Logger.log("geofence entered: " + gf.getRequestId()); 59 | String[] data = gf.getRequestId().split("@"); 60 | LatLng ll = new LatLng(Double.parseDouble(data[0]), 61 | Double.parseDouble(data[1])); 62 | String name = db.getNameForLocation(ll); 63 | if (name != null) { 64 | sendBroadcast(new Intent(this, Receiver.class) 65 | .setAction(Receiver.LOCATION_ENTERED_ACTION) 66 | .putExtra(Receiver.EXTRA_LOCATION_NAME, name)); 67 | break; 68 | } 69 | } 70 | db.close(); 71 | } 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 64 | 65 | 66 | 68 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | depuis au moins %d minutes 5 | tous les jours à %s 6 | toutes les %s 7 | Options avancées 8 | Plus d\'applications 9 | Donation 10 | Activer le Wi-Fi… 11 | au déverrouillage de l\'écran 12 | Éteindre le wi-fi quand… 13 | l\'écran est éteint 14 | connecté à aucun réseau 15 | Votre politique de veille Wi-Fi est configurée pour désactiver automatiquement le Wi-Fi dès que l\'écran s\'éteint. Vous pouvez changer la politique dans Options Wi-Fi avancées 16 | Options Wi-Fi avancées 17 | Paramètres non trouvés ! 18 | Min avant désactivation du Wi-Fi : 19 | Activer le Wi-Fi à : 20 | Désactiver le Wi-Fi à : 21 | Activer le Wi-Fi toutes les… 22 | Entrée incorrecte : le nombre doit être >= %1$d et <= %2$d 23 | au chargement de l\'appareil 24 | Ignore aussi le paramètre \"lorsque l\'écran est éteint\" pendant la charge 25 | 26 | 27 | 5 minutes 28 | 15 minutes 29 | 30 minutes 30 | 1 heure 31 | 2 heures 32 | 5 heures 33 | 10 heures 34 | 35 | 36 | Paramètres généraux 37 | Mode avion 38 | Ne pas activer le Wi-Fi en mode avion 39 | en entrant dans ces lieux 40 | Un seul lieu disponible dans la version gratuite de l\'application. Voulez-vous passer à la version pro maintenant ? 41 | Activer le Wi-Fi en entrant dans ces lieux : 42 | Utiliser la localisation cellulaire pour activer le Wi-Fi à des lieux spécifiés 43 | Le paramètre \"aucun délai réseau\" peut être trop court pour rechercher des localisations. Modifier à 5 min maintenant ? 44 | Wi-Fi déconnecté 45 | Appuyez pour sélectionner un réseau Wi-Fi 46 | Wi-Fi désactivé 47 | Appuyez pour activer 48 | Vos paramètres empêchent de déterminer votre localisation 49 | Intervalle : 50 | Scanne localisation actif 51 | Plus d\'info 52 | L\'application n\'a pas l\'autorisation d\'accéder à votre localisation 53 | 54 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/ScreenChangeDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.app.KeyguardManager; 20 | import android.app.Service; 21 | import android.content.BroadcastReceiver; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.content.IntentFilter; 25 | import android.os.Build; 26 | import android.os.IBinder; 27 | import android.os.PowerManager; 28 | 29 | /** 30 | * Background service which detects SCREEN_OFF events. 31 | *

32 | * Necessary for the 'turn wifi off if screen is off' option 33 | */ 34 | public class ScreenChangeDetector extends Service { 35 | 36 | final static String SCREEN_ON_ACTION = "SCREEN_ON"; 37 | final static String SCREEN_OFF_ACTION = "SCREEN_OFF"; 38 | 39 | private static BroadcastReceiver br; 40 | 41 | @Override 42 | public IBinder onBind(final Intent intent) { 43 | return null; 44 | } 45 | 46 | @Override 47 | public int onStartCommand(final Intent intent, int flags, int startId) { 48 | super.onStartCommand(intent, flags, startId); 49 | if (br == null) { 50 | if (BuildConfig.DEBUG) Logger.log("creating screen receiver"); 51 | br = new ScreenOffReceiver(); 52 | IntentFilter intf = new IntentFilter(); 53 | intf.addAction(Intent.ACTION_SCREEN_ON); 54 | intf.addAction(Intent.ACTION_SCREEN_OFF); 55 | registerReceiver(br, intf); 56 | } 57 | if (intent == null) { // service restarted 58 | // is display already off? 59 | if ((Build.VERSION.SDK_INT < 20 && 60 | !((PowerManager) getSystemService(POWER_SERVICE)).isScreenOn()) || 61 | (Build.VERSION.SDK_INT >= 20 && !APILevel20Wrapper.isScreenOn(this))) { 62 | sendBroadcast(new Intent(this, Receiver.class).setAction(SCREEN_OFF_ACTION)); 63 | } 64 | } 65 | 66 | return START_STICKY; 67 | } 68 | 69 | @Override 70 | public void onDestroy() { 71 | super.onDestroy(); 72 | if (BuildConfig.DEBUG) Logger.log("destroying screen receiver"); 73 | if (br != null) { 74 | try { 75 | unregisterReceiver(br); 76 | } catch (Exception e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | br = null; 81 | } 82 | 83 | static class ScreenOffReceiver extends BroadcastReceiver { 84 | @Override 85 | public void onReceive(final Context context, final Intent intent) { 86 | if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { 87 | context.sendBroadcast( 88 | new Intent(context, Receiver.class).setAction(SCREEN_OFF_ACTION)); 89 | } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction()) && 90 | !((KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE)) 91 | .inKeyguardRestrictedInputMode()) { 92 | // SCREEN_ON is only send if there is no lockscreen active! Otherwise the Receiver will get USER_PRESENT 93 | context.sendBroadcast( 94 | new Intent(context, Receiver.class).setAction(SCREEN_ON_ACTION)); 95 | } 96 | } 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/StatusPreference.java: -------------------------------------------------------------------------------- 1 | package de.j4velin.wifiAutoOff; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.net.ConnectivityManager; 6 | import android.net.wifi.WifiInfo; 7 | import android.net.wifi.WifiManager; 8 | import android.preference.Preference; 9 | import android.util.AttributeSet; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | public class StatusPreference extends Preference { 17 | 18 | private ImageView image; 19 | private TextView title; 20 | private TextView sub1; 21 | private TextView sub2; 22 | 23 | public StatusPreference(final Context context, final AttributeSet attrs) { 24 | super(context, attrs); 25 | } 26 | 27 | @Override 28 | protected View onCreateView(final ViewGroup parent) { 29 | super.onCreateView(parent); 30 | LayoutInflater li = 31 | (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 32 | View v = li.inflate(R.layout.statepreference, parent, false); 33 | image = v.findViewById(R.id.icon); 34 | title = v.findViewById(R.id.title); 35 | sub1 = v.findViewById(R.id.sub1); 36 | sub2 = v.findViewById(R.id.sub2); 37 | update(); 38 | return v; 39 | } 40 | 41 | /** 42 | * Called to update the status preference 43 | */ 44 | void update() { 45 | WifiManager wm = (WifiManager) getContext().getApplicationContext() 46 | .getSystemService(Context.WIFI_SERVICE); 47 | boolean connected = ((ConnectivityManager) getContext().getApplicationContext() 48 | .getSystemService(Context.CONNECTIVITY_SERVICE)) 49 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected(); 50 | if (title == null) return; 51 | if (wm.isWifiEnabled()) { 52 | if (!connected) { 53 | title.setText(R.string.no_connected); 54 | image.setColorFilter(Color.DKGRAY); 55 | sub1.setText(R.string.click_to_select_network); 56 | sub2.setVisibility(View.GONE); 57 | } else { 58 | WifiInfo wi = wm.getConnectionInfo(); 59 | String ssid = wi.getSSID(); 60 | if (ssid.contains("unknown ssid")) { 61 | // retrieve the SSID might require location permission on some Android versions 62 | ssid = getContext().getString(R.string.event_connected); 63 | } 64 | title.setText(ssid); 65 | image.setColorFilter(getContext().getResources().getColor(R.color.colorAccent)); 66 | updateSignal(); 67 | int ip = wi.getIpAddress(); 68 | sub2.setText(String.format("%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff), 69 | (ip >> 16 & 0xff), (ip >> 24 & 0xff))); 70 | sub2.setVisibility(View.VISIBLE); 71 | } 72 | } else { 73 | title.setText(R.string.wifi_not_enabled); 74 | image.setColorFilter(Color.LTGRAY); 75 | sub1.setText(R.string.click_to_turn_on); 76 | sub2.setVisibility(View.GONE); 77 | } 78 | } 79 | 80 | /** 81 | * Called to update the WiFi signal text 82 | * 83 | * @return true, if connected to a WiFi network 84 | */ 85 | boolean updateSignal() { 86 | WifiManager wm = (WifiManager) getContext().getApplicationContext() 87 | .getSystemService(Context.WIFI_SERVICE); 88 | boolean connected = ((ConnectivityManager) getContext().getApplicationContext() 89 | .getSystemService(Context.CONNECTIVITY_SERVICE)) 90 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting(); 91 | if (sub1 == null) return wm.isWifiEnabled() && connected; 92 | if (wm.isWifiEnabled() && connected) { 93 | WifiInfo wi = wm.getConnectionInfo(); 94 | try { 95 | sub1.setText(WifiManager.calculateSignalLevel(wi.getRssi(), 100) + "% - " + 96 | wi.getLinkSpeed() + " Mbps"); 97 | } catch (ArithmeticException e) { 98 | // might happen on Android 2.3 devices: https://code.google.com/p/android/issues/detail?id=2555 99 | sub1.setText(wi.getLinkSpeed() + " Mbps"); 100 | } 101 | return true; 102 | } else { 103 | return false; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/play/res/raw/map.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "elementType": "geometry", 4 | "stylers": [ 5 | { 6 | "color": "#33b5e5" 7 | } 8 | ] 9 | }, 10 | { 11 | "elementType": "labels.text.fill", 12 | "stylers": [ 13 | { 14 | "color": "#72cdef" 15 | } 16 | ] 17 | }, 18 | { 19 | "elementType": "labels.text.stroke", 20 | "stylers": [ 21 | { 22 | "color": "#0c4256" 23 | } 24 | ] 25 | }, 26 | { 27 | "featureType": "administrative.country", 28 | "elementType": "geometry.stroke", 29 | "stylers": [ 30 | { 31 | "color": "#4b6878" 32 | } 33 | ] 34 | }, 35 | { 36 | "featureType": "administrative.land_parcel", 37 | "elementType": "labels.text.fill", 38 | "stylers": [ 39 | { 40 | "color": "#64779e" 41 | } 42 | ] 43 | }, 44 | { 45 | "featureType": "administrative.province", 46 | "elementType": "geometry.stroke", 47 | "stylers": [ 48 | { 49 | "color": "#4b6878" 50 | } 51 | ] 52 | }, 53 | { 54 | "featureType": "landscape.man_made", 55 | "elementType": "geometry.stroke", 56 | "stylers": [ 57 | { 58 | "color": "#72cdef" 59 | } 60 | ] 61 | }, 62 | { 63 | "featureType": "landscape.natural", 64 | "elementType": "geometry", 65 | "stylers": [ 66 | { 67 | "color": "#72cdef" 68 | } 69 | ] 70 | }, 71 | { 72 | "featureType": "poi", 73 | "elementType": "geometry", 74 | "stylers": [ 75 | { 76 | "color": "#14789e" 77 | } 78 | ] 79 | }, 80 | { 81 | "featureType": "poi", 82 | "elementType": "labels.text.fill", 83 | "stylers": [ 84 | { 85 | "color": "#6f9ba5" 86 | } 87 | ] 88 | }, 89 | { 90 | "featureType": "poi", 91 | "elementType": "labels.text.stroke", 92 | "stylers": [ 93 | { 94 | "color": "#1d2c4d" 95 | } 96 | ] 97 | }, 98 | { 99 | "featureType": "poi.park", 100 | "elementType": "geometry.fill", 101 | "stylers": [ 102 | { 103 | "color": "#023e58" 104 | } 105 | ] 106 | }, 107 | { 108 | "featureType": "poi.park", 109 | "elementType": "labels.text.fill", 110 | "stylers": [ 111 | { 112 | "color": "#1582aa" 113 | } 114 | ] 115 | }, 116 | { 117 | "featureType": "road", 118 | "elementType": "geometry", 119 | "stylers": [ 120 | { 121 | "color": "#304a7d" 122 | } 123 | ] 124 | }, 125 | { 126 | "featureType": "road", 127 | "elementType": "labels.text.fill", 128 | "stylers": [ 129 | { 130 | "color": "#33b5e5" 131 | } 132 | ] 133 | }, 134 | { 135 | "featureType": "road", 136 | "elementType": "labels.text.stroke", 137 | "stylers": [ 138 | { 139 | "color": "#1d2c4d" 140 | } 141 | ] 142 | }, 143 | { 144 | "featureType": "road.highway", 145 | "elementType": "geometry", 146 | "stylers": [ 147 | { 148 | "color": "#72cdef" 149 | } 150 | ] 151 | }, 152 | { 153 | "featureType": "road.highway", 154 | "elementType": "geometry.stroke", 155 | "stylers": [ 156 | { 157 | "color": "#0c516b" 158 | } 159 | ] 160 | }, 161 | { 162 | "featureType": "road.highway", 163 | "elementType": "labels.text.fill", 164 | "stylers": [ 165 | { 166 | "color": "#b0d5ce" 167 | } 168 | ] 169 | }, 170 | { 171 | "featureType": "road.highway", 172 | "elementType": "labels.text.stroke", 173 | "stylers": [ 174 | { 175 | "color": "#023e58" 176 | } 177 | ] 178 | }, 179 | { 180 | "featureType": "transit", 181 | "elementType": "labels.text.fill", 182 | "stylers": [ 183 | { 184 | "color": "#b3e3f7" 185 | } 186 | ] 187 | }, 188 | { 189 | "featureType": "transit.line", 190 | "elementType": "geometry.fill", 191 | "stylers": [ 192 | { 193 | "color": "#72cdef" 194 | } 195 | ] 196 | }, 197 | { 198 | "featureType": "transit.station", 199 | "elementType": "geometry", 200 | "stylers": [ 201 | { 202 | "color": "#0c455a" 203 | } 204 | ] 205 | }, 206 | { 207 | "featureType": "water", 208 | "elementType": "geometry", 209 | "stylers": [ 210 | { 211 | "color": "#0e1626" 212 | } 213 | ] 214 | }, 215 | { 216 | "featureType": "water", 217 | "elementType": "labels.text.fill", 218 | "stylers": [ 219 | { 220 | "color": "#4e6d70" 221 | } 222 | ] 223 | } 224 | ] -------------------------------------------------------------------------------- /src/play/res/layout/locations.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 26 | 27 | 38 | 39 | 47 | 48 | 58 | 59 | 69 | 70 | 82 | 83 | 92 | 93 | 98 | 99 | 108 | 109 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/APILevel26ForegroundService.java: -------------------------------------------------------------------------------- 1 | package de.j4velin.wifiAutoOff; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Notification; 5 | import android.app.NotificationChannel; 6 | import android.app.NotificationManager; 7 | import android.app.PendingIntent; 8 | import android.app.Service; 9 | import android.content.BroadcastReceiver; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.content.IntentFilter; 13 | import android.content.SharedPreferences; 14 | import android.os.Build; 15 | import android.os.IBinder; 16 | import android.preference.PreferenceManager; 17 | import android.provider.Settings; 18 | import android.support.v4.app.NotificationCompat; 19 | 20 | @TargetApi(Build.VERSION_CODES.O) 21 | public class APILevel26ForegroundService extends Service { 22 | 23 | private final static String CHANNEL_ID = "foregroundService"; 24 | 25 | public static void start(final Context context) { 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 27 | createNotificationChannel(context); 28 | context.startForegroundService(new Intent(context, APILevel26ForegroundService.class)); 29 | } 30 | } 31 | 32 | private static void createNotificationChannel(final Context context) { 33 | NotificationManager mNotificationManager = 34 | (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 35 | NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "WiFi Automatic", 36 | NotificationManager.IMPORTANCE_LOW); 37 | channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 38 | channel.setDescription(context.getString(R.string.notification_desc)); 39 | mNotificationManager.createNotificationChannel(channel); 40 | } 41 | 42 | private final static BroadcastReceiver RECEIVER = new Receiver(); 43 | private final static IntentFilter[] FILTERS = 44 | new IntentFilter[]{new IntentFilter("android.net.wifi.STATE_CHANGE"), 45 | new IntentFilter("android.net.wifi.WIFI_STATE_CHANGED"), 46 | new IntentFilter("android.net.wifi.p2p.CONNECTION_STATE_CHANGE"), 47 | new IntentFilter("android.intent.action.ACTION_POWER_CONNECTED"), 48 | new IntentFilter("android.intent.action.ACTION_POWER_DISCONNECTED")}; 49 | private static ScreenChangeDetector.ScreenOffReceiver screenOffReceiver; 50 | private static boolean registered; 51 | 52 | @Override 53 | public IBinder onBind(Intent intent) { 54 | return null; 55 | } 56 | 57 | @Override 58 | public void onCreate() { 59 | super.onCreate(); 60 | if (BuildConfig.DEBUG) Logger.log("API26ForegroundService onCreate"); 61 | } 62 | 63 | @Override 64 | public int onStartCommand(Intent intent, int flags, int startId) { 65 | startForeground(42, 66 | new NotificationCompat.Builder(this, CHANNEL_ID).setSmallIcon(R.drawable.icon_black) 67 | .setContentTitle("WiFi Automatic") 68 | .setContentText(getString(R.string.hide_notification)).setContentIntent( 69 | PendingIntent.getActivity(this, 1, 70 | new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) 71 | .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()) 72 | .putExtra(Settings.EXTRA_CHANNEL_ID, CHANNEL_ID), 0)) 73 | .build()); 74 | synchronized (CHANNEL_ID) { 75 | if (!registered) { 76 | for (IntentFilter filter : FILTERS) { 77 | registerReceiver(RECEIVER, filter); 78 | } 79 | registered = true; 80 | } 81 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 82 | if (prefs.getBoolean("off_screen_off", true) || prefs.getBoolean("on_unlock", true)) { 83 | if (screenOffReceiver == null) { 84 | screenOffReceiver = new ScreenChangeDetector.ScreenOffReceiver(); 85 | } 86 | registerReceiver(screenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON)); 87 | registerReceiver(screenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); 88 | registerReceiver(RECEIVER, new IntentFilter(Intent.ACTION_USER_PRESENT)); 89 | } else if (screenOffReceiver != null) { 90 | try { 91 | unregisterReceiver(screenOffReceiver); 92 | } catch (Exception e) { 93 | // ignore 94 | } 95 | screenOffReceiver = null; 96 | } 97 | } 98 | return START_STICKY; 99 | } 100 | 101 | @Override 102 | public void onDestroy() { 103 | super.onDestroy(); 104 | if (BuildConfig.DEBUG) Logger.log("API26ForegroundService onDestroy"); 105 | synchronized (CHANNEL_ID) { 106 | registered = false; 107 | try { 108 | unregisterReceiver(RECEIVER); 109 | if (screenOffReceiver != null) { 110 | unregisterReceiver(screenOffReceiver); 111 | } 112 | } catch (Throwable t) { 113 | if (BuildConfig.DEBUG) Logger.log(t); 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/play/java/de/j4velin/wifiAutoOff/Map.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.Manifest; 19 | import android.graphics.Color; 20 | import android.os.Bundle; 21 | import android.support.v4.app.ActivityCompat; 22 | import android.support.v4.content.PermissionChecker; 23 | import android.support.v7.app.AppCompatActivity; 24 | 25 | import com.google.android.gms.common.api.GoogleApiClient; 26 | import com.google.android.gms.location.LocationServices; 27 | import com.google.android.gms.maps.CameraUpdateFactory; 28 | import com.google.android.gms.maps.GoogleMap; 29 | import com.google.android.gms.maps.OnMapReadyCallback; 30 | import com.google.android.gms.maps.SupportMapFragment; 31 | import com.google.android.gms.maps.model.CircleOptions; 32 | import com.google.android.gms.maps.model.LatLng; 33 | import com.google.android.gms.maps.model.MapStyleOptions; 34 | 35 | public class Map extends AppCompatActivity implements OnMapReadyCallback { 36 | 37 | private final static int REQUEST_PERMISSIONS = 1; 38 | 39 | private GoogleApiClient mGoogleApiClient; 40 | 41 | private void showMap() { 42 | setContentView(R.layout.map); 43 | ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) 44 | .getMapAsync(this); 45 | } 46 | 47 | @Override 48 | public void onCreate(final Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | 51 | if (PermissionChecker 52 | .checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != 53 | PermissionChecker.PERMISSION_GRANTED || PermissionChecker 54 | .checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != 55 | PermissionChecker.PERMISSION_GRANTED) { 56 | ActivityCompat.requestPermissions(Map.this, 57 | new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, 58 | Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSIONS); 59 | } else { 60 | showMap(); 61 | } 62 | } 63 | 64 | @Override 65 | public void onRequestPermissionsResult(int requestCode, final String[] permissions, 66 | final int[] grantResults) { 67 | if (requestCode == REQUEST_PERMISSIONS) { 68 | if (grantResults.length >= 2 && 69 | grantResults[0] == PermissionChecker.PERMISSION_GRANTED && 70 | grantResults[1] == PermissionChecker.PERMISSION_GRANTED) { 71 | showMap(); 72 | } else { 73 | finish(); 74 | } 75 | } else { 76 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 77 | } 78 | } 79 | 80 | @SuppressWarnings("MissingPermission") 81 | @Override 82 | public void onMapReady(final GoogleMap mMap) { 83 | MapStyleOptions style = MapStyleOptions.loadRawResourceStyle(this, R.raw.map); 84 | mMap.setMapStyle(style); 85 | LatLng location = getIntent().getParcelableExtra("location"); 86 | if (location == null) { 87 | mGoogleApiClient = new GoogleApiClient.Builder(this).addApi(LocationServices.API) 88 | .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { 89 | @Override 90 | public void onConnected(final Bundle bundle) { 91 | android.location.Location l = LocationServices.FusedLocationApi 92 | .getLastLocation(mGoogleApiClient); 93 | if (l != null && mMap.getCameraPosition().zoom <= 2) { 94 | mMap.moveCamera(CameraUpdateFactory.newLatLngZoom( 95 | new LatLng(l.getLatitude(), l.getLongitude()), 16)); 96 | } 97 | mGoogleApiClient.disconnect(); 98 | } 99 | 100 | @Override 101 | public void onConnectionSuspended(int cause) { 102 | if (BuildConfig.DEBUG) Logger.log("connection suspended: " + cause); 103 | } 104 | }).build(); 105 | 106 | mGoogleApiClient.connect(); 107 | 108 | mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() { 109 | @Override 110 | public void onMapClick(final LatLng center) { 111 | getIntent().putExtra("location", center); 112 | setResult(RESULT_OK, getIntent()); 113 | finish(); 114 | } 115 | }); 116 | } else { 117 | mMap.addCircle(new CircleOptions().center(location).radius(100).strokeColor(Color.BLUE) 118 | .fillColor(Color.argb(64, 0, 0, 255))); 119 | mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 16)); 120 | } 121 | 122 | mMap.setMyLocationEnabled(true); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/res/values-it/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | per almeno %d min 6 | ogni giorno alle %s 7 | ogni %s 8 | Impostazioni WiFi avanzate 9 | Altre apps 10 | Donazione 11 | Accendi il WiFi… 12 | quando il device viene sbloccato 13 | Spegni il WiFi quando… 14 | lo schermo e` spento 15 | non sei connesso ad alcuna rete 16 | Le tue impostazioni del WiFi sono impostate per disabilitare automaticamente il WiFi quando lo schermo si spegne. Puoi cambiare le impostazioni nel menu \'Impostazioni avanzate WiFi\' di Android 17 | 18 | Impostazioni WiFi avanzate 19 | Impostazione non trovata! 20 | Minuti prima di spegnere il WiFi: 21 | Accendi il WiFi alle: 22 | Spegni il WiFi alle: 23 | Accendi il WiFi ogni … 24 | Input invalido: il numero deve essere >= %1$d e <= 25 | %2$d 26 | 27 | quando e` in carica 28 | Ignora l\'impostazione \"quando lo schermo e` spento\" mentre e` in carica 29 | 30 | 31 | 32 | 5 min 33 | 15 min 34 | 30 min 35 | 1 ora 36 | 2 ore 37 | 5 ore 38 | 10 ore 39 | 40 | 41 | Impostazioni Generali 42 | Modalita` aereo 43 | Non abilitare il WiFi in modalita` aereo 44 | quanto ci si trova in queste posizioni 45 | Solo una posizione e` supportata nella versione free dell\'app. Vuoi installare la versione pro ora? 46 | 47 | Accendi il WiFi quando sei in queste posizioni: 48 | Usa le informazioni della posizione della cella per accendere il WiFi in una determinata posizione 49 | 50 | WiFi disconnesso 51 | Clicca per selezionare la rete WiFi 52 | WiFi disabilitato 53 | Clicca per accendere 54 | Le tue impostazioni non permettono all\'app di determinare la tua posizione 55 | Intervallo: 56 | Attiva lo scan della posizione 57 | Altre informazioni 58 | L\'App non ha i permessi per accedere alla tua posizione 59 | Nessun log ancora 60 | Mostra gli ultimi eventi che hanno cambiato lo stato del WiFi 61 | Log 62 | Non accendere il WiFi perche` il device e` in modalita` aereo 63 | Accendi il WiFi 64 | Spegni il WiFi 65 | Posizione inserita: %s 66 | L\'evento schermo spento e` stato ignorato perche` il device e` in carica 67 | 68 | Device sbloccato 69 | WiFi connesso 70 | WiFi disconnesso 71 | WiFi abilitato 72 | WiFi disablitato 73 | Caricabatterie connesso 74 | Caricabatterie disconnesso 75 | Timer dello schermo spento cancellato 76 | Timer senza rete cancellato 77 | Timer dello schermo impostato (%d min) 78 | Timer senza rete impostato (%d min) 79 | Cancella log 80 | Accendi/Spegni 81 | Non accendere il WiFi se l\'hotspot WiFi e` attivo 82 | Impossibile cambiare lo stato del WiFi 83 | Impossibile cambiare lo stato del WiFi: %s 84 | Il device e` in modalita` aereo 85 | Attenzione: Con la tua versione di Android, l\'app non puo` cambiare lo stato del WiFi 86 | mentre il device e` in modalita` aereo! 87 | 88 | 89 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /src/main/res/values-pt/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | por pelo menos %d minutos 6 | todos dias às %s 7 | cada %s 8 | Ajustes avançados de WiFi 9 | Mais apps 10 | Doar 11 | Ligue o WiFi… 12 | ao desbloquear o dispositivo 13 | Desligar WiFi quando… 14 | a tela desliga 15 | não está conectado a ninhuma rede 16 | Sua política de hibernação de Wi-Fi está definida para desativar automaticamente 17 | o WiFi quando a tela é desligada. Você pode alterar a política nos \'ajustes avançados de WiFi\' do Android 18 | 19 | Ajustes av. de WiFi 20 | Nenhuma configuração encontrada! 21 | Minutos antes de desligar o WiFi: 22 | Ligue o WiFi em: 23 | Desligue o WiFi em: 24 | Ligue o WiFi a cada … 25 | Entrada inválida: o número deve ser >= %1$d y <= 26 | %2$d 27 | 28 | durante o carregamento 29 | Ignorar também as configurações \"quando a tela desliga\" durante o carregamento 30 | 31 | 32 | 33 | 5 minutos 34 | 15 minutos 35 | 30 minutos 36 | 1 hora 37 | 2 horas 38 | 5 horas 39 | 10 horas 40 | 41 | 42 | Configurações Gerais 43 | Modo avião 44 | Não habilitar WiFi ao estrar em modo avião 45 | ao entrar nestas localizações 46 | A versão gratuita do app permite uma só Localização. Deseja 47 | atualizar para a versão pro? 48 | 49 | Ligue o WiFi ao entrar nestes locais: 50 | Use as informações de localização do seu telefone para ligar o WiFi em locais 51 | definidas 52 | 53 | Wi-Fi desconectado 54 | Pressione para selecionar uma rede WiFi 55 | Wifi desativado 56 | Pressione para ligar 57 | Sua configuração atual impede que o aplicativo detecte sua 58 | Localização 59 | 60 | Intervalo: 61 | Verificação de localização ativa 62 | Mais informações 63 | O aplicativo não tem permissão para acessar sua localização 64 | Ainda não há registros 65 | Mostra os últimos eventos que mudaram o status do WiFi 66 | Registro 67 | O WiFi não será ativado porque o dispositivo está no modo avião 68 | Ativando WiFi 69 | Desativando WiFi 70 | Localização inserida: %s 71 | Status da tela ignorado devido ao dispositivo estar conectado 72 | para uma tomada 73 | 74 | Dispositivo desbloqueado 75 | WiFi conectado 76 | Wi-Fi desconectado 77 | Wi-Fi habilitado 78 | Wifi desativado 79 | Conectado a uma tomada externa 80 | Desconectado da tomada 81 | O temporizador de desligamento da tela foi cancelado 82 | Nenhum timer de rede foi cancelado 83 | Temporizador de desligamento de tela atribuído (%d min) 84 | Nenhum temporizador atribuído à rede (%d min) 85 | Apagar registro de logs 86 | Ativar/Desativar 87 | Não ative o WiFi se houver um ponto de acesso WiFi ativo 88 | Não é possível alterar o status do WiFi 89 | Não é possível alterar o status do WiFi: %s 90 | O dispositivo está em modo avião 91 | Aviso: Na sua versão Android, os aplicativos não podem alterar o 92 | Status do WiFi se o dispositivo estiver no modo avião! 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | по истечении %d мин. 5 | каждый день в %s 6 | каждые %s 7 | Расширенные настройки WiFi 8 | Другие приложения 9 | Пожертвовать 10 | Включать WiFi… 11 | когда устройство разблокировано 12 | Отключать WiFi… 13 | когда экран отключен 14 | когда нет сетевой активности 15 | Ваши настройки спящего режима WiFi, будут отключать WiFi как только погаснет экран. Вы можете изменить это, перейдя в \'Расширенные настройки WiFi\' вашего Android 16 | Расш. настройки WiFi 17 | Настройки не найдены! 18 | Минуты перед отключением WiFi: 19 | Включить WiFi в: 20 | Отключить WiFi в: 21 | Включать WiFi каждые … 22 | Ошибка ввода: Число должно быть >= %1$d и <= %2$d 23 | когда устройство заряжается 24 | Будет проигнорирована настройка \'когда экран отключен\' 25 | 26 | 27 | 5 мин. 28 | 15 мин. 29 | 30 мин. 30 | 1 час 31 | 2 часа 32 | 5 часов 33 | 10 часов 34 | 35 | 36 | Общие настройки 37 | Режим полета 38 | Не включать WiFi в \'режиме полета\' 39 | при нахождении в этих местах 40 | В бесплатной версии доступна настройка только одного местоположения. Вы хотите перейти на Pro версию сейчас? 41 | Включать WiFi при нахождении в этих местах: 42 | Использовать информацию о своем местоположении, для включения WiFi в определённых местах 43 | WiFi не подключен 44 | Нажмите для выбора WiFi сети 45 | WiFi выключен 46 | Нажмите чтобы включить 47 | Настройки вашего телефона запрещают приложению определять местоположение 48 | Интервал: 49 | Активная проверка местоположения 50 | Подробнее 51 | У приложения нет прав доступа к вашему местоположению 52 | В журнале нет записей 53 | Просмотр последних событий в работе приложения 54 | Журнал 55 | WiFi не был включен, потому что устройство находится в \'режиме полета\' 56 | Включение WiFi 57 | Выключение WiFi 58 | Нахождение в местоположении: %s 59 | Отключение экрана не произошло, так как устройство подключено к зарядке 60 | Устройство разблокировано 61 | WiFi подключен 62 | WiFi отключен 63 | WiFi включен 64 | WiFi выключен 65 | Подключено внешнее питание 66 | Отключено внешнее питание 67 | Таймер отключения экрана отменен 68 | Таймер сетевой активности отменен 69 | Запущен таймер отключения экрана (%d мин) 70 | Запущен таймер сетевой активности (%d мин) 71 | Экран выключен 72 | Экран включен/string> 73 | Очистить 74 | Вкл/Выкл 75 | WiFi не был переключен, так как он находится в режиме \'точка доступа\' 76 | Невозможно переключить WiFi 77 | Невозможно переключить WiFi: %s 78 | Устройство находится в \'режиме полета\' 79 | Внимание: На вашей версии Android нельзя переключать WiFi, если устройство находится в \'режиме полета\'! 80 | Приложение неактивно 81 | Приложение активно 82 | Нажмите сюда, что бы скрыть это уведомление 83 | Это уведомление необходимо для работы WiFi Automatic на устройствах Android 8+. Вы можете без проблем отключить его. 84 | Эта функция не работает без разрешенного доступа к местоположению 85 | Для включения WiFi в зависимости от вашего местоположения требуется разрешение на доступ к местоположению, даже если приложение закрыто или не активно. Вы хотите дать это разрешение сейчас? 86 | 87 | -------------------------------------------------------------------------------- /src/play/java/de/j4velin/wifiAutoOff/GeofenceUpdateService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.Manifest; 19 | import android.app.PendingIntent; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.SharedPreferences; 23 | import android.os.Bundle; 24 | import android.support.annotation.NonNull; 25 | import android.support.v4.app.JobIntentService; 26 | import android.support.v4.content.PermissionChecker; 27 | 28 | import com.google.android.gms.common.ConnectionResult; 29 | import com.google.android.gms.common.api.GoogleApiClient; 30 | import com.google.android.gms.location.Geofence; 31 | import com.google.android.gms.location.GeofencingRequest; 32 | import com.google.android.gms.location.LocationRequest; 33 | import com.google.android.gms.location.LocationServices; 34 | 35 | import java.util.List; 36 | 37 | public class GeofenceUpdateService extends JobIntentService implements 38 | GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { 39 | 40 | private final static int LOCATION_RANGE_METER = 200; 41 | private static final int JOB_ID = 4242; 42 | private GoogleApiClient mLocationClient; 43 | 44 | public static void enqueueJob(Context context) { 45 | try { 46 | enqueueWork(context, GeofenceUpdateService.class, JOB_ID, new Intent()); 47 | } catch (Exception e) { 48 | if (BuildConfig.DEBUG) Logger.log(e); 49 | } 50 | } 51 | 52 | @Override 53 | protected void onHandleWork(@NonNull Intent intent) { 54 | if (mLocationClient == null) { 55 | mLocationClient = new GoogleApiClient.Builder(this).addApi(LocationServices.API) 56 | .addConnectionCallbacks(this).addOnConnectionFailedListener(this).build(); 57 | mLocationClient.connect(); 58 | } 59 | } 60 | 61 | @Override 62 | public void onConnected(final Bundle bundle) { 63 | if (mLocationClient == null) return; // should not happen? 64 | if (BuildConfig.DEBUG) Logger.log("removing all fences"); 65 | PendingIntent pi = PendingIntent 66 | .getService(this, 0, new Intent(this, GeoFenceService.class), 67 | PendingIntent.FLAG_UPDATE_CURRENT); 68 | LocationServices.GeofencingApi.removeGeofences(mLocationClient, pi); 69 | LocationServices.FusedLocationApi.removeLocationUpdates(mLocationClient, pi); 70 | Database database = Database.getInstance(this); 71 | List locations = database.getLocations(); 72 | database.close(); 73 | 74 | SharedPreferences prefs = getSharedPreferences("locationPrefs", MODE_PRIVATE); 75 | 76 | if (BuildConfig.DEBUG) Logger.log("re-adding all " + locations.size() + " fences"); 77 | if (!locations.isEmpty()) { 78 | GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); 79 | builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); 80 | for (Location l : locations) { 81 | try { 82 | builder.addGeofence(new Geofence.Builder() 83 | .setCircularRegion(l.coords.latitude, l.coords.longitude, 84 | LOCATION_RANGE_METER) 85 | .setRequestId(l.coords.latitude + "@" + l.coords.longitude) 86 | .setExpirationDuration(Geofence.NEVER_EXPIRE) 87 | .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER).build()); 88 | } catch (Exception e) { 89 | if (BuildConfig.DEBUG) Logger.log(e); 90 | } 91 | } 92 | try { 93 | if (PermissionChecker 94 | .checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == 95 | PermissionChecker.PERMISSION_GRANTED && PermissionChecker 96 | .checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == 97 | PermissionChecker.PERMISSION_GRANTED) { 98 | LocationServices.GeofencingApi 99 | .addGeofences(mLocationClient, builder.build(), pi); 100 | if (prefs.getBoolean("active", false)) { 101 | LocationRequest mLocationRequest = new LocationRequest(); 102 | mLocationRequest.setInterval(prefs.getInt("interval", 15) * 60000); 103 | mLocationRequest.setFastestInterval(5000); 104 | mLocationRequest.setSmallestDisplacement(50f); 105 | mLocationRequest 106 | .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); 107 | LocationServices.FusedLocationApi 108 | .requestLocationUpdates(mLocationClient, mLocationRequest, pi); 109 | } 110 | } else { 111 | if (BuildConfig.DEBUG) Logger.log("no location permission"); 112 | } 113 | } catch (Exception iae) { 114 | if (BuildConfig.DEBUG) Logger.log(iae); 115 | } 116 | } 117 | disconnect(); 118 | } 119 | 120 | @Override 121 | public void onConnectionSuspended(int i) { 122 | disconnect(); 123 | } 124 | 125 | private void disconnect() { 126 | if (BuildConfig.DEBUG) Logger.log("GeofenceUpdateService disconnect"); 127 | if (mLocationClient != null) mLocationClient.disconnect(); 128 | mLocationClient = null; 129 | stopSelf(); 130 | } 131 | 132 | @Override 133 | public void onConnectionFailed(final ConnectionResult connectionResult) { 134 | disconnect(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | for at least %d min 5 | everyday at %s 6 | every %s 7 | Advanced WiFi settings 8 | More apps 9 | Donate 10 | Turn WiFi on… 11 | when device gets unlocked 12 | Turn WiFi off when… 13 | screen is off 14 | not connected to any network 15 | Your WiFi sleep policy is set to automatically disable WiFi as soon 16 | as the display goes off. You can change the policy in the Android \'Advanced WiFi settings\' 17 | 18 | Adv. WiFi settings 19 | Settings not found! 20 | Minutes before turning off WiFi: 21 | Turn WiFi on at: 22 | Turn WiFi off at: 23 | Turn WiFi on every … 24 | Invalid input: Number has to be >= %1$d and <= 25 | %2$d 26 | 27 | when charging 28 | Also ignores the \"when screen is off\" setting while charging 29 | 30 | 31 | 32 | 5 min 33 | 15 min 34 | 30 min 35 | 1 hour 36 | 2 hours 37 | 5 hours 38 | 10 hours 39 | 40 | 41 | General settings 42 | Airplane mode 43 | Don\'t enable WiFi when in airplane mode 44 | when entering these locations 45 | Only one location is support in the free version of the app. Do you want 46 | to upgrade to the pro version now? 47 | 48 | Turn on WiFi when entering these locations: 49 | Use cell location information to turn WiFi on at specified 50 | locations 51 | 52 | WiFi disconnected 53 | Click to select WiFi network 54 | WiFi disabled 55 | Click to turn on 56 | Your settings prevent the app from detect your 57 | location 58 | 59 | Interval: 60 | Active location scanning 61 | More info 62 | App does not have permission to access your location 63 | No log entries yet 64 | Shows the last events which triggered a WiFi change 65 | Log 66 | Not turning WiFi on because device is in airplane mode 67 | Turning WiFi on 68 | Turning WiFi off 69 | Location entered: %s 70 | Screen off event ignored because device is connected 71 | to external power 72 | 73 | Device unlocked 74 | WiFi connected 75 | WiFi disconnected 76 | WiFi enabled 77 | WiFi disabled 78 | External power connected 79 | External power disconnected 80 | Screen off timer canceled 81 | No network timer canceled 82 | Screen off timer set (%d min) 83 | No network timer set (%d min) 84 | Display turned off 85 | Display turned on 86 | Delete log 87 | Turn on/off 88 | Not turning WiFi on as WiFi hotspot is active 89 | Unable to change WiFi state 90 | Unable to change WiFi state: %s 91 | Device is in airplane mode 92 | Notice: On your Android version, apps can not change the WiFi 93 | state while the device is in airplane mode! 94 | 95 | App disabled 96 | App enabled 97 | Click here to hide this notification 98 | This notification is necessary to keep WiFi Automatic running 99 | on Android 8+ devices. You can safely disable it from being shown. 100 | 101 | This feature will not work without location permission 102 | Enabling WiFi based on your location requires the permission to access your location, 103 | even when the app is closed or not in use. Do you want to grant this permission now? 104 | -------------------------------------------------------------------------------- /src/main/res/values-es/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | por al menos %d minutos 6 | cada día a las %s 7 | cada %s 8 | Ajustes avanzados de WiFi 9 | Más aplicaciones 10 | Hacer una donación 11 | Encender WiFi… 12 | al desbloquear el dispositivo 13 | Apagar WiFi cuando… 14 | la pantalla se apague 15 | no está conectado a ningúna red 16 | Su política de suspensión de Wi-Fi está configurada para desactivar 17 | automáticamente el WiFi al apagarse la pantalla. Puede cambiar la política en los 18 | \'Ajustes avanzados de WiFi\' de Android 19 | 20 | Ajustes av. de WiFi 21 | ¡No se han encontrado ajustes! 22 | Minutos antes de apagar el WiFi: 23 | Encender WiFi a las: 24 | Apagar WiFi a las: 25 | Encender WiFi cada … 26 | Entrada no válida: el número debe ser >= %1$d y 27 | <= %2$d 28 | 29 | durante la carga 30 | También ignora la configuración \"cuando la pantalla se apague\" 31 | durante la carga 32 | 33 | 34 | 35 | 5 minutos 36 | 15 minutos 37 | 30 minutos 38 | 1 hora 39 | 2 horas 40 | 5 horas 41 | 10 horas 42 | 43 | 44 | Ajustes generales 45 | Modo avión 46 | No activar el WiFi al estar en modo avión 47 | al entrar en estas ubicaciones 48 | La versión gratuita de la aplicación permite una única ubicación. ¿Quiere 49 | actualizar a la versión pro? 50 | 51 | Encender el WiFi al entrar en estas ubicaciones: 52 | Usar la información de ubicación del teléfono para encender el 53 | WiFi en las ubicaciones especificadas 54 | 55 | WiFi desconectado 56 | Pulsa para seleccionar una red WiFi 57 | WiFi desactivado 58 | Pulsa para encender 59 | Sus configuraciones impiden que la aplicación detecte 60 | su ubicación 61 | 62 | Intervalo: 63 | Escaneo de ubicación activo 64 | Más info 65 | La app no tiene permiso para acceder a su ubicación 66 | Aún no hay registros 67 | Muestra los últimos eventos que cambiaron el estado del WiFi 68 | Registro 69 | No se activará el WiFi ya que el dispositivo se encuentra en modo avión 70 | Activando WiFi 71 | Desactivando WiFi 72 | Ubicación introducida: %s 73 | No se ha apagado la pantalla debido a que el 74 | dispositivo está conectado a una toma de corriente 75 | 76 | Dispositivo desbloqueado 77 | WiFi conectado 78 | WiFi desconectado 79 | WiFi activado 80 | WiFi desactivado 81 | Conectado a una toma de corriente 82 | Desconectado de la toma de corriente 83 | Se ha cancelado el temporizador de pantalla apagada 84 | Se ha cancelado el temporizador de sin red 85 | Temporizador de pantalla apagada asignado (%d min) 86 | Temporizador de sin red asignado (%d min) 87 | Pantalla apagada 88 | Pantalla encendida 89 | Borrar registro 90 | Activar/Desactivar 91 | No se activará el WiFi ya que hay un punto de acceso WiFi activo 92 | No se puede cambiar el estado del WiFi 93 | No se puede cambiar el estado del WiFi: %s 94 | El dispositivo está en modo avión 95 | Aviso: en su versión de Android, las aplicaciones no pueden 96 | cambiar el estado del WiFi cuando el dispositivo está en modo avión. 97 | 98 | Aplicación desactivada 99 | Aplicación activada 100 | Pulse aquí para ocultar esta notificación 101 | Esta notificación es necesaria para que WiFi Automatic se siga 102 | ejecutando en dispositivos Android 8+. Puede ocultarla sin ningún problema. 103 | 104 | Esta característica no funcionará sin el permiso de ubicación 105 | 106 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.content.ContentValues; 19 | import android.content.Context; 20 | import android.database.Cursor; 21 | import android.database.sqlite.SQLiteDatabase; 22 | import android.database.sqlite.SQLiteDatabaseLockedException; 23 | import android.database.sqlite.SQLiteOpenHelper; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | public class Log { 29 | 30 | /** 31 | * Time to keep the logs in ms 32 | */ 33 | final static long KEEP_DURATION = 3 * 24 * 60 * 60 * 1000; // 3 days 34 | 35 | public enum Type { 36 | WIFI_ON(R.drawable.event_wifi_on), WIFI_CONNECTED(R.drawable.event_wifi_on), 37 | WIFI_OFF(R.drawable.event_wifi_off), WIFI_DISCONNECTED(R.drawable.event_wifi_disconnected), 38 | LOCATION_ENTERED(R.drawable.event_location_entered), TIMER(R.drawable.event_timer), 39 | AIRPLANE_MODE(R.drawable.event_airplane_mode), SCREEN_OFF(R.drawable.event_display_off), 40 | SCREEN_ON(R.drawable.event_display_on), UNLOCKED(R.drawable.event_unlock), 41 | AC_CONNECTED(R.drawable.event_ac_connected), 42 | AC_DISCONNECTED(R.drawable.event_ac_disconnected), HOTSPOT(R.drawable.event_hotspot), 43 | ERROR(R.drawable.event_error), APP_DISABLED(R.drawable.event_app_disabled), 44 | APP_ENABLED(R.drawable.event_app_enabled); 45 | 46 | public final int drawable; 47 | 48 | Type(int drawable) { 49 | this.drawable = drawable; 50 | } 51 | } 52 | 53 | private Log() { 54 | } 55 | 56 | /** 57 | * Inserts an event in the persistent log 58 | * 59 | * @param context the context 60 | * @param text the text describing the event 61 | * @param type the type of the event 62 | */ 63 | public static void insert(final Context context, final String text, final Type type) { 64 | ContentValues values = new ContentValues(); 65 | values.put("date", System.currentTimeMillis()); 66 | values.put("info", text); 67 | values.put("type", type.name()); 68 | Database db = new Database(context); 69 | try { 70 | db.getWritableDatabase().insert(Database.DB_NAME, null, values); 71 | } catch (Exception e) { 72 | if (BuildConfig.DEBUG) Logger.log(e); 73 | } finally { 74 | db.close(); 75 | } 76 | if (BuildConfig.DEBUG) Logger.log(text); 77 | } 78 | 79 | /** 80 | * Inserts an event in the persistent log 81 | * 82 | * @param context the context 83 | * @param text a string resource id which describes this event 84 | * @param type the type of the event 85 | */ 86 | public static void insert(final Context context, int text, final Type type) { 87 | insert(context, context.getString(text), type); 88 | } 89 | 90 | /** 91 | * Gets the log 92 | * 93 | * @param context the context 94 | * @param num the maximum number of log entries to load or a number <= 0 to load all entries 95 | * @return a list containing the log entries in descending date order (newest first) 96 | */ 97 | public static List getLog(final Context context, int num) { 98 | List result; 99 | Database db = new Database(context); 100 | Cursor c = db.getReadableDatabase() 101 | .query(Database.DB_NAME, new String[]{"date", "info", "type"}, null, null, null, 102 | null, "date DESC", num > 0 ? String.valueOf(num) : null); 103 | if (c != null) { 104 | result = new ArrayList<>(c.getCount()); 105 | if (c.moveToFirst()) { 106 | do { 107 | result.add(new Item(c.getLong(0), c.getString(1), c.getString(2))); 108 | } while (c.moveToNext()); 109 | } 110 | c.close(); 111 | } else { 112 | result = new ArrayList<>(0); 113 | } 114 | db.close(); 115 | return result; 116 | } 117 | 118 | /** 119 | * Deletes all log entries which are older then the given duration 120 | * 121 | * @param context the context 122 | * @param duration the duration in ms 123 | */ 124 | public static void deleteOldLogs(final Context context, long duration) { 125 | Database db = new Database(context); 126 | try { 127 | int deleted = db.getWritableDatabase().delete(Database.DB_NAME, "date < ?", 128 | new String[]{String.valueOf(System.currentTimeMillis() - duration)}); 129 | if (BuildConfig.DEBUG) Logger.log("deleted " + deleted + " old log entries"); 130 | } catch (SQLiteDatabaseLockedException e) { 131 | if (BuildConfig.DEBUG) Logger.log("cant delete log: database locked"); 132 | } catch (Throwable t) { 133 | if (BuildConfig.DEBUG) Logger.log("cant delete log: " + t.getMessage()); 134 | } finally { 135 | db.close(); 136 | } 137 | } 138 | 139 | /** 140 | * Container class describing a log item 141 | */ 142 | public static class Item { 143 | 144 | final long date; 145 | final String text; 146 | final Type type; 147 | 148 | public Item(long date, final String text, final String type) { 149 | this.date = date; 150 | this.text = text; 151 | this.type = Type.valueOf(type); 152 | } 153 | } 154 | 155 | private static class Database extends SQLiteOpenHelper { 156 | 157 | private final static String DB_NAME = "log"; 158 | private final static int DB_VERSION = 1; 159 | 160 | private Database(final Context context) { 161 | super(context, DB_NAME, null, DB_VERSION); 162 | } 163 | 164 | @Override 165 | public void onCreate(final SQLiteDatabase db) { 166 | db.execSQL("CREATE TABLE " + DB_NAME + " (date INTEGER, info TEXT, type TEXT)"); 167 | } 168 | 169 | @Override 170 | public void onUpgrade(final SQLiteDatabase db, int oldVersion, int newVersion) { 171 | 172 | } 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /src/play/java/de/j4velin/wifiAutoOff/Database.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.j4velin.wifiAutoOff; 17 | 18 | import android.content.ContentValues; 19 | import android.content.Context; 20 | import android.database.Cursor; 21 | import android.database.sqlite.SQLiteDatabase; 22 | import android.database.sqlite.SQLiteOpenHelper; 23 | 24 | import com.google.android.gms.maps.model.LatLng; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | 30 | public class Database extends SQLiteOpenHelper { 31 | 32 | private static final int DATABASE_VERSION = 1; 33 | private static Database instance; 34 | 35 | private static final AtomicInteger openCounter = new AtomicInteger(); 36 | 37 | private Database(final Context context) { 38 | super(context, "wifiautomatic", null, DATABASE_VERSION); 39 | } 40 | 41 | public static synchronized Database getInstance(final Context c) { 42 | if (instance == null) { 43 | instance = new Database(c.getApplicationContext()); 44 | } 45 | openCounter.incrementAndGet(); 46 | return instance; 47 | } 48 | 49 | @Override 50 | public void close() { 51 | if (openCounter.decrementAndGet() == 0) { 52 | super.close(); 53 | } 54 | } 55 | 56 | @Override 57 | public void onCreate(final SQLiteDatabase db) { 58 | db.execSQL("CREATE TABLE IF NOT EXISTS locations (name TEXT, lat DOUBLE, lon DOUBLE);"); 59 | } 60 | 61 | @Override 62 | public void onUpgrade(final SQLiteDatabase db, int oldVersion, int newVersion) { 63 | 64 | } 65 | 66 | /** 67 | * Gets a list of saved locations 68 | * 69 | * @return the list of locations, might be empty 70 | */ 71 | public List getLocations() { 72 | Cursor c = getReadableDatabase() 73 | .query("locations", new String[]{"name", "lat", "lon"}, null, null, null, null, 74 | null); 75 | c.moveToFirst(); 76 | List re = new ArrayList<>(c.getCount()); 77 | while (!c.isAfterLast()) { 78 | if (BuildConfig.DEBUG) 79 | Logger.log("added location: " + c.getString(0) + " " + c.getDouble(1) + " " + 80 | c.getDouble(2)); 81 | re.add(new Location(c.getString(0), new LatLng(c.getDouble(1), c.getDouble(2)))); 82 | c.moveToNext(); 83 | } 84 | c.close(); 85 | return re; 86 | } 87 | 88 | /** 89 | * Saves a location 90 | * 91 | * @param name the name (e.g. address or thelike) 92 | * @param coords the latitude, longitude coordinate 93 | */ 94 | public void addLocation(final String name, final LatLng coords) { 95 | ContentValues values = new ContentValues(); 96 | values.put("name", name); 97 | values.put("lat", coords.latitude); 98 | values.put("lon", coords.longitude); 99 | getWritableDatabase().insert("locations", null, values); 100 | } 101 | 102 | /** 103 | * Deletes a location 104 | * 105 | * @param coords the coordinates of the location to delete 106 | */ 107 | public void deleteLocation(final LatLng coords) { 108 | if (BuildConfig.DEBUG) Logger.log("deleting " + coords.toString() + " contained? " + 109 | (getNameForLocation(coords) != null)); 110 | getWritableDatabase().delete("locations", "lat LIKE ? AND lon LIKE ?", 111 | new String[]{String.valueOf(coords.latitude).substring(0, 8) + "%", 112 | String.valueOf(coords.longitude).substring(0, 8) + "%"}); 113 | } 114 | 115 | /** 116 | * Gets the saved name for the given coordinates 117 | * 118 | * @param coords the location to check 119 | * @return the name for the given locaiton or null, if that location is not a saved location 120 | */ 121 | public String getNameForLocation(final LatLng coords) { 122 | String lat = String.valueOf(coords.latitude); 123 | String lon = String.valueOf(coords.longitude); 124 | if (lat.length() > 9) lat = lat.substring(0, 8); 125 | if (lon.length() > 9) lon = lon.substring(0, 8); 126 | Cursor c = getReadableDatabase() 127 | .query("locations", new String[]{"name"}, "lat LIKE ? AND lon LIKE ?", 128 | new String[]{lat + "%", lon + "%"}, null, null, null); 129 | String result; 130 | if (c.moveToFirst()) { 131 | result = c.getString(0); 132 | } else { 133 | result = null; 134 | if (BuildConfig.DEBUG) 135 | Logger.log("location not in database: " + coords.latitude + "," + coords.longitude); 136 | } 137 | c.close(); 138 | return result; 139 | } 140 | 141 | /** 142 | * Checks if the given location is within the given range of any saved location 143 | * 144 | * @param current the location to test 145 | * @return true, if 'current' is within range of any saved location 146 | */ 147 | public boolean inRangeOfLocation(final android.location.Location current) { 148 | String lat = String.valueOf(current.getLatitude()); 149 | String lon = String.valueOf(current.getLongitude()); 150 | 151 | Cursor c = getReadableDatabase().query("locations", new String[]{"lat", "lon"}, 152 | "ABS(lat - ?) < 0.1 AND ABS(lon - ?) < 0.1", new String[]{lat, lon}, null, null, 153 | null); 154 | if (BuildConfig.DEBUG) 155 | Logger.log(c.getCount() + " locations found which might be in range"); 156 | boolean inRange = false; 157 | if (c.moveToFirst()) { 158 | android.location.Location location = new android.location.Location("tester"); 159 | while (!inRange && !c.isAfterLast()) { 160 | location.setLatitude(c.getDouble(0)); 161 | location.setLongitude(c.getDouble(1)); 162 | inRange = location.distanceTo(current) < current.getAccuracy(); 163 | if (BuildConfig.DEBUG) Logger.log("distance to " + location + ": " + 164 | location.distanceTo(current)); 165 | c.moveToNext(); 166 | } 167 | } 168 | c.close(); 169 | return inRange; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | für mindestens %d min 5 | täglich um %s 6 | alle %s 7 | Erweiterte WLAN-Einstellungen 8 | Weitere Apps 9 | Spenden 10 | Schalte WLAN ein… 11 | wenn das Gerät entsperrt wird 12 | Schalte WLAN aus… 13 | wenn das Display aus ist 14 | wenn kein Netzwerk in Reichweite 15 | Die WLAN-Optionen sind momentan so eingestellt, dass das WLAN 16 | automatisch abgeschaltet wird, wenn das Display aus geht. Dieses Verhalten kann in den 17 | \'Erweiterten WLAN-Einstellungen\' von Android geändert werden. 18 | 19 | Erw. WLAN-Einstellungen 20 | Einstellungen nicht gefunden! 21 | Dauer in Minuten bevor WLAN ausgeschaltet werden 22 | soll: 23 | 24 | Uhrzeit, zu welcher WLAN eingeschaltet werden soll: 25 | Uhrzeit, zu welcher WLAN abgeschaltet werden soll: 26 | Schalte WLAN alle … ein 27 | Fehlerhafte Eingabe: Zahl muss zwischen %1$d und 28 | %2$d sein 29 | 30 | beim Laden 31 | Ignoriert während des Ladens auch die \"wenn das Display aus ist\" 32 | Einstellung 33 | 34 | 35 | 36 | 5 Minuten 37 | 15 Minuten 38 | 30 Minuten 39 | 1 Stunde 40 | 2 Stunden 41 | 5 Stunden 42 | 10 Stunden 43 | 44 | 45 | Allgemein 46 | Flugmodus 47 | Schalte WLAN nicht ein, wenn sich das Gerät im Flugmodus 48 | befindet 49 | 50 | beim Betreten dieser Orte 51 | In der kostenlosen Version der App wird nur ein Ort unterstützt. Möchtest 52 | du jetzt auf die Pro-Version aufwerten? 53 | 54 | Beim Betreten folgender Orte wird das WLAN eingeschaltet: 55 | Verwende Funkmasten-Informationen um WLAN an festgelegten Orten 56 | einzuschalten 57 | 58 | \'Kein Netz in Reichweite\' Einstellung könnte für die 59 | Standort-Optionen zu kurz sein. Jetzt auf die Einstellung \'5 min\' ändern? 60 | 61 | WLAN nicht verbunden 62 | Hier klicken um WLAN-Netzwerk auszuwählen 63 | WLAN ausgeschaltet 64 | Hier klicken zum einzuschalten 65 | Deine Einstellungen verbieten der App deinen Standort 66 | zu bestimmen, diese Funktion wird daher nicht funktionieren. Klicke hier um die 67 | Standort-Einstellungen zu ändern 68 | 69 | Intervall: 70 | Aktive Standort-Bestimmung 71 | Mehr dazu 72 | Die App hat keine Berechtigung zum Zugiff auf den Standort 73 | Keine Log-Einträge vorhanden 74 | Zeigt die letzten von der App registrierten Ereignisse 75 | Log 76 | WLAN nicht aktiviert da sich das Gerät im Flugmodus befindet 77 | 78 | Schalte WLAN ein 79 | Schalte WLAN aus 80 | Standort betreten: %s 81 | Bildschirm wurde ausgeschaltet, aber Gerät ist ans 82 | Stromnetz angeschloßen 83 | 84 | Gerät entsperrt 85 | WLAN verbunden 86 | WLAN Verbindung verloren 87 | WLAN eingeschaltet 88 | WLAN ausgeschaltet 89 | Mit Stromversorgung verbunden 90 | Stromversorgung unterbrochen 91 | "Display aus" Timer abgebrochen 92 | "Keine Verbindung" Timer abgebrochen 93 | "Display aus" Timer gesetzt (%d min) 94 | "Keine Verbindung" Timer gesetzt (%d min) 95 | Display ausgeschaltet 96 | Display eingeschaltet 97 | Log löschen 98 | Ein-/Ausschalten 99 | WiFi Hotspot aktiv, WLAN wird nicht eingeschaltet 100 | WLAN Status kann nicht geändert werden 101 | WLAN Status kann nicht geändert werden: %s 102 | Gerät ist im Flugmodus 103 | Hinweis: In deiner Android Version kann der WLAN Status nicht 104 | durch Apps geändert werden, wenn sich das Gerät im Flugmdus befindet! 105 | 106 | App ausgeschaltet 107 | App eingeschaltet 108 | Klicke hier um diese Benachrichtigung auszublenden 109 | Diese Benachrichtung wird benötigt, damit WiFi Automatic im 110 | Hintergrund laufen kann. Die Benachrichtung kann in den Einstellungen ausgeblendet werden 111 | ohne das die Funktionalität der App beeinträchtigt wird. 112 | 113 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/Start.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.app.AlarmManager; 20 | import android.app.PendingIntent; 21 | import android.content.ComponentName; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.content.SharedPreferences; 25 | import android.content.pm.PackageManager; 26 | import android.os.Build; 27 | import android.preference.PreferenceManager; 28 | 29 | import java.util.Calendar; 30 | import java.util.Date; 31 | 32 | /** 33 | * Utility class to set all necessary timers / start the background service 34 | */ 35 | abstract class Start { 36 | 37 | /** 38 | * Creates the ON_AT and OFF_AT timers 39 | * 40 | * @param c the contextl 41 | */ 42 | static void createTimers(final Context c) { 43 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); 44 | AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE); 45 | 46 | Calendar cal = Calendar.getInstance(); 47 | 48 | cal.set(Calendar.SECOND, 1); 49 | cal.set(Calendar.MILLISECOND, 0); 50 | 51 | if (prefs.getBoolean("on_at", false)) { 52 | String[] time = prefs.getString("on_at_time", Receiver.ON_AT_TIME).split(":"); 53 | 54 | cal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time[0])); 55 | cal.set(Calendar.MINUTE, Integer.valueOf(time[1])); 56 | 57 | if (cal.getTimeInMillis() <= System.currentTimeMillis()) 58 | cal.add(Calendar.DAY_OF_MONTH, 1); 59 | 60 | PendingIntent pi = PendingIntent.getBroadcast(c, Receiver.TIMER_ON_AT, 61 | new Intent(c, Receiver.class).putExtra("changeWiFi", true).setAction("ON_AT"), 62 | PendingIntent.FLAG_UPDATE_CURRENT); 63 | Util.setTimer(c, AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi); 64 | if (BuildConfig.DEBUG) Logger.log( 65 | "ON_AT alarm set at " + new Date(cal.getTimeInMillis()).toLocaleString()); 66 | 67 | } else { // stop timer 68 | am.cancel(PendingIntent.getBroadcast(c, Receiver.TIMER_ON_AT, 69 | new Intent(c, Receiver.class).putExtra("changeWiFi", true).setAction("ON_AT"), 70 | PendingIntent.FLAG_UPDATE_CURRENT)); 71 | } 72 | if (prefs.getBoolean("off_at", false)) { 73 | String[] time = prefs.getString("off_at_time", Receiver.OFF_AT_TIME).split(":"); 74 | 75 | cal = Calendar.getInstance(); 76 | 77 | cal.set(Calendar.SECOND, 1); 78 | cal.set(Calendar.MILLISECOND, 0); 79 | 80 | cal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time[0])); 81 | cal.set(Calendar.MINUTE, Integer.valueOf(time[1])); 82 | 83 | if (cal.getTimeInMillis() <= System.currentTimeMillis()) 84 | cal.add(Calendar.DAY_OF_MONTH, 1); 85 | 86 | PendingIntent pi = PendingIntent.getBroadcast(c, Receiver.TIMER_OFF_AT, 87 | new Intent(c, Receiver.class).putExtra("changeWiFi", false).setAction("OFF_AT"), 88 | PendingIntent.FLAG_UPDATE_CURRENT); 89 | Util.setTimer(c, AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pi); 90 | if (BuildConfig.DEBUG) Logger.log( 91 | "OFF_AT alarm set at " + new Date(cal.getTimeInMillis()).toLocaleString()); 92 | } else { // stop timer 93 | am.cancel(PendingIntent.getBroadcast(c, Receiver.TIMER_OFF_AT, 94 | new Intent(c, Receiver.class).putExtra("changeWiFi", false).setAction("OFF_AT"), 95 | PendingIntent.FLAG_UPDATE_CURRENT)); 96 | } 97 | if (BuildConfig.DEBUG) Logger.log("ON/OFF timers set"); 98 | } 99 | 100 | /** 101 | * Sets all necessary timers / starts the background service depending on 102 | * the user settings 103 | * 104 | * @param c the context 105 | */ 106 | @SuppressWarnings("deprecation") 107 | static void start(final Context c) { 108 | createTimers(c); 109 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); 110 | AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE); 111 | if (prefs.getBoolean("on_every", false)) { 112 | long interval = prefs.contains("on_every_time_min") ? 113 | 1000 * 60 * prefs.getInt("on_every_time_min", Receiver.ON_EVERY_TIME_MIN) : 114 | AlarmManager.INTERVAL_HOUR * 115 | prefs.getInt("on_every_time", Receiver.ON_EVERY_TIME_MIN / 60); 116 | am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, 117 | PendingIntent.getBroadcast(c, Receiver.TIMER_ON_EVERY, 118 | new Intent(c, Receiver.class).putExtra("changeWiFi", true) 119 | .setAction("ON_EVERY"), PendingIntent.FLAG_UPDATE_CURRENT)); 120 | } else { // stop timer 121 | am.cancel(PendingIntent.getBroadcast(c, Receiver.TIMER_ON_EVERY, 122 | new Intent(c, Receiver.class).putExtra("changeWiFi", true) 123 | .setAction("ON_EVERY"), PendingIntent.FLAG_UPDATE_CURRENT)); 124 | } 125 | 126 | c.getPackageManager().setComponentEnabledSetting(new ComponentName(c, UnlockReceiver.class), 127 | prefs.getBoolean("on_unlock", true) && 128 | Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 129 | PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 130 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 131 | PackageManager.DONT_KILL_APP); 132 | 133 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { 134 | // on O and later, the APILevel26ForegroundService handles this 135 | if (prefs.getBoolean("off_screen_off", true) || prefs.getBoolean("on_unlock", true)) { 136 | c.startService(new Intent(c, ScreenChangeDetector.class)); 137 | } else { 138 | c.stopService(new Intent(c, ScreenChangeDetector.class)); 139 | } 140 | } 141 | 142 | GeofenceUpdateService.enqueueJob(c); 143 | APILevel26ForegroundService.start(c); 144 | 145 | if (BuildConfig.DEBUG) Logger.log("all timers set/cleared"); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/play/aidl/com/android/vending/billing/IInAppBillingService.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.vending.billing; 18 | 19 | import android.os.Bundle; 20 | 21 | /** 22 | * InAppBillingService is the service that provides in-app billing version 3 and beyond. 23 | * This service provides the following features: 24 | * 1. Provides a new API to get details of in-app items published for the app including 25 | * price, type, title and description. 26 | * 2. The purchase flow is synchronous and purchase information is available immediately 27 | * after it completes. 28 | * 3. Purchase information of in-app purchases is maintained within the Google Play system 29 | * till the purchase is consumed. 30 | * 4. An API to consume a purchase of an inapp item. All purchases of one-time 31 | * in-app items are consumable and thereafter can be purchased again. 32 | * 5. An API to get current purchases of the user immediately. This will not contain any 33 | * consumed purchases. 34 | * 35 | * All calls will give a response code with the following possible values 36 | * RESULT_OK = 0 - success 37 | * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog 38 | * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested 39 | * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase 40 | * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API 41 | * RESULT_ERROR = 6 - Fatal error during the API action 42 | * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned 43 | * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned 44 | */ 45 | interface IInAppBillingService { 46 | /** 47 | * Checks support for the requested billing API version, package and in-app type. 48 | * Minimum API version supported by this interface is 3. 49 | * @param apiVersion the billing version which the app is using 50 | * @param packageName the package name of the calling app 51 | * @param type type of the in-app item being purchased "inapp" for one-time purchases 52 | * and "subs" for subscription. 53 | * @return RESULT_OK(0) on success, corresponding result code on failures 54 | */ 55 | int isBillingSupported(int apiVersion, String packageName, String type); 56 | 57 | /** 58 | * Provides details of a list of SKUs 59 | * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle 60 | * with a list JSON strings containing the productId, price, title and description. 61 | * This API can be called with a maximum of 20 SKUs. 62 | * @param apiVersion billing API version that the Third-party is using 63 | * @param packageName the package name of the calling app 64 | * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" 65 | * @return Bundle containing the following key-value pairs 66 | * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on 67 | * failure as listed above. 68 | * "DETAILS_LIST" with a StringArrayList containing purchase information 69 | * in JSON format similar to: 70 | * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00", 71 | * "title : "Example Title", "description" : "This is an example description" }' 72 | */ 73 | Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle); 74 | 75 | /** 76 | * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, 77 | * the type, a unique purchase token and an optional developer payload. 78 | * @param apiVersion billing API version that the app is using 79 | * @param packageName package name of the calling app 80 | * @param sku the SKU of the in-app item as published in the developer console 81 | * @param type the type of the in-app item ("inapp" for one-time purchases 82 | * and "subs" for subscription). 83 | * @param developerPayload optional argument to be sent back with the purchase information 84 | * @return Bundle containing the following key-value pairs 85 | * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on 86 | * failure as listed above. 87 | * "BUY_INTENT" - PendingIntent to start the purchase flow 88 | * 89 | * The Pending intent should be launched with startIntentSenderForResult. When purchase flow 90 | * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. 91 | * If the purchase is successful, the result data will contain the following key-value pairs 92 | * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on 93 | * failure as listed above. 94 | * "INAPP_PURCHASE_DATA" - String in JSON format similar to 95 | * '{"orderId":"12999763169054705758.1371079406387615", 96 | * "packageName":"com.example.app", 97 | * "productId":"exampleSku", 98 | * "purchaseTime":1345678900000, 99 | * "purchaseToken" : "122333444455555", 100 | * "developerPayload":"example developer payload" }' 101 | * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that 102 | * was signed with the private key of the developer 103 | * TODO: change this to app-specific keys. 104 | */ 105 | Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, 106 | String developerPayload); 107 | 108 | /** 109 | * Returns the current SKUs owned by the user of the type and package name specified along with 110 | * purchase information and a signature of the data to be validated. 111 | * This will return all SKUs that have been purchased in V3 and managed items purchased using 112 | * V1 and V2 that have not been consumed. 113 | * @param apiVersion billing API version that the app is using 114 | * @param packageName package name of the calling app 115 | * @param type the type of the in-app items being requested 116 | * ("inapp" for one-time purchases and "subs" for subscription). 117 | * @param continuationToken to be set as null for the first call, if the number of owned 118 | * skus are too many, a continuationToken is returned in the response bundle. 119 | * This method can be called again with the continuation token to get the next set of 120 | * owned skus. 121 | * @return Bundle containing the following key-value pairs 122 | * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on 123 | * failure as listed above. 124 | * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs 125 | * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information 126 | * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures 127 | * of the purchase information 128 | * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the 129 | * next set of in-app purchases. Only set if the 130 | * user has more owned skus than the current list. 131 | */ 132 | Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken); 133 | 134 | /** 135 | * Consume the last purchase of the given SKU. This will result in this item being removed 136 | * from all subsequent responses to getPurchases() and allow re-purchase of this item. 137 | * @param apiVersion billing API version that the app is using 138 | * @param packageName package name of the calling app 139 | * @param purchaseToken token in the purchase information JSON that identifies the purchase 140 | * to be consumed 141 | * @return 0 if consumption succeeded. Appropriate error values for failures. 142 | */ 143 | int consumePurchase(int apiVersion, String packageName, String purchaseToken); 144 | } 145 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /src/main/java/de/j4velin/wifiAutoOff/Receiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Thomas Hoffmann 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package de.j4velin.wifiAutoOff; 18 | 19 | import android.annotation.SuppressLint; 20 | import android.app.AlarmManager; 21 | import android.app.PendingIntent; 22 | import android.content.BroadcastReceiver; 23 | import android.content.Context; 24 | import android.content.Intent; 25 | import android.content.SharedPreferences; 26 | import android.net.NetworkInfo; 27 | import android.net.wifi.SupplicantState; 28 | import android.net.wifi.WifiManager; 29 | import android.net.wifi.p2p.WifiP2pInfo; 30 | import android.net.wifi.p2p.WifiP2pManager; 31 | import android.os.Build; 32 | import android.os.PowerManager; 33 | import android.provider.Settings; 34 | import android.provider.Settings.SettingNotFoundException; 35 | import android.widget.Toast; 36 | 37 | import java.lang.reflect.Method; 38 | 39 | /** 40 | * Class for receiving various events and react on them. 41 | */ 42 | public class Receiver extends BroadcastReceiver { 43 | 44 | public final static String LOCATION_ENTERED_ACTION = "LOCATION_ENTERED"; 45 | // to prevent SecurityException: Not allowed to send ACTION_POWER_CONNECTED 46 | public final static String POWER_CONNECTED = "POWER_CONNECTED"; 47 | public final static String EXTRA_LOCATION_NAME = "name"; 48 | private static NetworkInfo.State previousState = null; 49 | 50 | private static final int TIMER_SCREEN_OFF = 1; 51 | private static final int TIMER_NO_NETWORK = 2; 52 | static final int TIMER_ON_AT = 3; 53 | static final int TIMER_OFF_AT = 4; 54 | static final int TIMER_ON_EVERY = 5; 55 | 56 | static final int TIMEOUT_NO_NETWORK = 5; 57 | static final int TIMEOUT_SCREEN_OFF = 10; 58 | static final int ON_EVERY_TIME_MIN = 120; 59 | static final String ON_AT_TIME = "8:00"; 60 | static final String OFF_AT_TIME = "22:00"; 61 | 62 | /** 63 | * Starts one of the timers to turn WiFi off 64 | * 65 | * @param context the context 66 | * @param id TIMER_SCREEN_OFF or TIMER_NO_NETWORK 67 | * @param time in min 68 | */ 69 | private void startTimer(final Context context, int id, int time) { 70 | String action = (id == TIMER_SCREEN_OFF) ? "SCREEN_OFF_TIMER" : "NO_NETWORK_TIMER"; 71 | Intent timerIntent = 72 | new Intent(context, Receiver.class).putExtra("timer", id).setAction(action); 73 | if (PendingIntent.getBroadcast(context, id, timerIntent, PendingIntent.FLAG_NO_CREATE) == 74 | null) { 75 | Util.setTimer(context, AlarmManager.RTC_WAKEUP, 76 | System.currentTimeMillis() + 60000 * time, PendingIntent 77 | .getBroadcast(context, id, timerIntent, 78 | PendingIntent.FLAG_UPDATE_CURRENT)); 79 | Log.insert(context, context.getString( 80 | id == TIMER_SCREEN_OFF ? R.string.event_screen_off_timer : 81 | R.string.event_no_network_timer, time), Log.Type.TIMER); 82 | } else if (BuildConfig.DEBUG) { 83 | Logger.log("timer for action " + action + " already set"); 84 | } 85 | } 86 | 87 | /** 88 | * Stops the timer 89 | * 90 | * @param context the context 91 | * @param id TIMER_SCREEN_OFF or TIMER_NO_NETWORK 92 | * @return true, if timer was actually active 93 | */ 94 | private boolean stopTimer(final Context context, int id) { 95 | Intent timerIntent = new Intent(context, Receiver.class).putExtra("timer", id) 96 | .setAction(id == TIMER_SCREEN_OFF ? "SCREEN_OFF_TIMER" : "NO_NETWORK_TIMER"); 97 | PendingIntent pendingIntent = 98 | PendingIntent.getBroadcast(context, id, timerIntent, PendingIntent.FLAG_NO_CREATE); 99 | if (pendingIntent != null) { 100 | ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).cancel(pendingIntent); 101 | pendingIntent.cancel(); 102 | Log.insert(context, (id == TIMER_SCREEN_OFF) ? R.string.event_screen_off_canceled : 103 | R.string.event_no_network_canceled, Log.Type.TIMER); 104 | } 105 | return pendingIntent != null; 106 | } 107 | 108 | /** 109 | * Get default shared preferences 110 | * 111 | * @param context the context 112 | * @return default SharedPreferences for given context 113 | */ 114 | @SuppressLint("InlinedApi") 115 | private static SharedPreferences getSharedPreferences(final Context context) { 116 | String prefFileName = context.getPackageName() + "_preferences"; 117 | return context.getSharedPreferences(prefFileName, Context.MODE_MULTI_PROCESS); 118 | } 119 | 120 | /** 121 | * Changes the WiFi state 122 | * 123 | * @param context the context 124 | * @param on true to turn WiFi on, false to turn it off 125 | */ 126 | @SuppressWarnings("deprecation") 127 | private static void changeWiFi(final Context context, boolean on) { 128 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 129 | try { 130 | if (APILevel17Wrapper.isAirplaneModeOn(context)) { 131 | Log.insert(context, context.getString(R.string.unable_to_change_reason, 132 | context.getString(R.string.error_reason_airplane)), Log.Type.ERROR); 133 | if (BuildConfig.DEBUG) 134 | Logger.log("Unable to change WiFi state: In airplane mode on Android 8.1"); 135 | } 136 | } catch (final SettingNotFoundException e) { 137 | if (BuildConfig.DEBUG) Logger.log(e); 138 | } 139 | } 140 | SharedPreferences prefs = getSharedPreferences(context); 141 | if (on && prefs.getBoolean("airplane", true)) { 142 | // check for airplane mode 143 | if (BuildConfig.DEBUG) Logger.log("checking for airplane mode"); 144 | try { 145 | if (android.os.Build.VERSION.SDK_INT >= 146 | android.os.Build.VERSION_CODES.JELLY_BEAN_MR1 ? 147 | APILevel17Wrapper.isAirplaneModeOn(context) : Settings.System 148 | .getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON) == 149 | 1) { 150 | Log.insert(context, R.string.event_airplane, Log.Type.AIRPLANE_MODE); 151 | return; 152 | } 153 | } catch (final SettingNotFoundException e) { 154 | // not airplane setting found? Handle like not in airplane mode 155 | // then 156 | if (BuildConfig.DEBUG) Logger.log(e); 157 | e.printStackTrace(); 158 | } 159 | } 160 | if (on) { 161 | // check WiFi hotspot state (dont turn on WiFi if hotspot is active) 162 | WifiManager wifi = (WifiManager) context.getApplicationContext() 163 | .getSystemService(Context.WIFI_SERVICE); 164 | try { 165 | Method m = wifi.getClass().getDeclaredMethod("isWifiApEnabled"); 166 | if ((boolean) m.invoke(wifi)) { 167 | Log.insert(context, R.string.hotspot_active, Log.Type.HOTSPOT); 168 | return; 169 | } 170 | } catch (Exception e) { 171 | if (BuildConfig.DEBUG) Logger.log(e); 172 | e.printStackTrace(); 173 | } 174 | } 175 | try { 176 | WifiManager wm = ((WifiManager) context.getApplicationContext() 177 | .getSystemService(Context.WIFI_SERVICE)); 178 | // do we need to change at all? 179 | if (wm.isWifiEnabled() != on) { 180 | Log.insert(context, on ? R.string.event_turn_on : R.string.event_turn_off, 181 | on ? Log.Type.WIFI_ON : Log.Type.WIFI_OFF); 182 | boolean success = wm.setWifiEnabled(on); 183 | if (!success) { 184 | Log.insert(context, R.string.unable_to_change, Log.Type.ERROR); 185 | if (BuildConfig.DEBUG) Logger.log("Unable to change WiFi state"); 186 | } 187 | } 188 | } catch (Exception e) { 189 | Toast.makeText(context, "Can not change WiFi state: " + e.getClass().getName(), 190 | Toast.LENGTH_LONG).show(); 191 | } 192 | } 193 | 194 | private static boolean isWiFiConnected(final Context context) { 195 | WifiManager wm = ((WifiManager) context.getApplicationContext() 196 | .getSystemService(Context.WIFI_SERVICE)); 197 | return (wm != null && wm.getConnectionInfo() != null && 198 | wm.getConnectionInfo().getSupplicantState() == SupplicantState.COMPLETED); 199 | } 200 | 201 | @SuppressLint("InlinedApi") 202 | @Override 203 | public void onReceive(final Context context, final Intent intent) { 204 | final String action = intent.getAction(); 205 | if (BuildConfig.DEBUG) Logger.log("received: " + action); 206 | SharedPreferences prefs = getSharedPreferences(context); 207 | if (intent.hasExtra("timer")) { 208 | // one of the timers expired -> turn wifi off 209 | changeWiFi(context, false); 210 | stopTimer(context, intent.getIntExtra("timer", 0)); 211 | } else if (intent.hasExtra("changeWiFi")) { 212 | // for "ON AT" or "OFF AT" options 213 | changeWiFi(context, intent.getBooleanExtra("changeWiFi", false)); 214 | Start.createTimers(context); 215 | } else { 216 | switch (action) { 217 | case LOCATION_ENTERED_ACTION: 218 | if (!((WifiManager) context.getApplicationContext() 219 | .getSystemService(Context.WIFI_SERVICE)).isWifiEnabled()) { 220 | Log.insert(context, context.getString(R.string.event_location, 221 | intent.getStringExtra(EXTRA_LOCATION_NAME)), 222 | Log.Type.LOCATION_ENTERED); 223 | if (prefs.getBoolean("off_no_network", true)) { 224 | // start the timer before actually turning on the WiFi to set the NO_NETWORK 225 | // timer to at least 10 min. The set timer in the following WIFI_STATE_CHANGED_ACTION 226 | // will then have no effect, as the timer is already set 227 | startTimer(context, TIMER_NO_NETWORK, Math.max(10, 228 | prefs.getInt("no_network_timeout", TIMEOUT_NO_NETWORK))); 229 | } 230 | changeWiFi(context, true); 231 | } // else: WiFi is already enabled, do nothing 232 | break; 233 | case ScreenChangeDetector.SCREEN_OFF_ACTION: 234 | if (prefs.getBoolean("off_screen_off", true)) { 235 | if (!prefs.getBoolean("ignore_screen_off", false)) { 236 | // screen went off -> start TIMER_SCREEN_OFF 237 | Log.insert(context, R.string.event_screen_off, Log.Type.SCREEN_OFF); 238 | startTimer(context, TIMER_SCREEN_OFF, 239 | prefs.getInt("screen_off_timeout", TIMEOUT_SCREEN_OFF)); 240 | } else { 241 | Log.insert(context, R.string.event_display_off_ignored_ac, 242 | Log.Type.SCREEN_OFF); 243 | } 244 | } 245 | break; 246 | case UnlockReceiver.USER_PRESENT_ACTION: 247 | case Intent.ACTION_USER_PRESENT: 248 | case ScreenChangeDetector.SCREEN_ON_ACTION: 249 | if (action.equals(ScreenChangeDetector.SCREEN_ON_ACTION)) { 250 | Log.insert(context, R.string.event_screen_on, Log.Type.SCREEN_ON); 251 | } else { 252 | Log.insert(context, R.string.event_unlocked, Log.Type.UNLOCKED); 253 | } 254 | // user unlocked the device -> stop TIMER_SCREEN_OFF, might turn on 255 | // WiFi 256 | stopTimer(context, TIMER_SCREEN_OFF); 257 | if (prefs.getBoolean("on_unlock", true)) { 258 | boolean noNetTimer = stopTimer(context, TIMER_NO_NETWORK); 259 | if (((WifiManager) context.getApplicationContext() 260 | .getSystemService(Context.WIFI_SERVICE)).isWifiEnabled()) { 261 | if (noNetTimer && prefs.getBoolean("off_no_network", true)) { 262 | // if WiFi is already turned on, just restart the NO_NETWORK timer 263 | startTimer(context, TIMER_NO_NETWORK, 264 | prefs.getInt("no_network_timeout", TIMEOUT_NO_NETWORK)); 265 | } 266 | } else { 267 | changeWiFi(context, true); 268 | } 269 | } 270 | break; 271 | case WifiManager.NETWORK_STATE_CHANGED_ACTION: 272 | final NetworkInfo nwi = 273 | intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 274 | if (nwi == null) return; 275 | if (nwi.isConnected()) { 276 | if (!nwi.getState().equals(previousState)) { 277 | Log.insert(context, R.string.event_connected, Log.Type.WIFI_CONNECTED); 278 | } 279 | stopTimer(context, TIMER_NO_NETWORK); 280 | } else if (nwi.getState().equals(NetworkInfo.State.DISCONNECTED)) { 281 | if (!nwi.getState().equals(previousState)) { 282 | Log.insert(context, R.string.event_disconnected, 283 | Log.Type.WIFI_DISCONNECTED); 284 | } 285 | if (prefs.getBoolean("off_no_network", true)) { 286 | startTimer(context, TIMER_NO_NETWORK, 287 | prefs.getInt("no_network_timeout", TIMEOUT_NO_NETWORK)); 288 | } 289 | } 290 | previousState = nwi.getState(); 291 | break; 292 | case WifiManager.WIFI_STATE_CHANGED_ACTION: 293 | if (intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 294 | WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED) { 295 | Log.insert(context, R.string.event_enabled, Log.Type.WIFI_ON); 296 | if (isWiFiConnected(context)) { 297 | if (BuildConfig.DEBUG) { 298 | Logger.log("Wifi already connected"); 299 | } 300 | } else { 301 | if (prefs.getBoolean("off_no_network", true)) { 302 | startTimer(context, TIMER_NO_NETWORK, 303 | prefs.getInt("no_network_timeout", TIMEOUT_NO_NETWORK)); 304 | } 305 | } 306 | if (prefs.getBoolean("off_screen_off", true) && 307 | ((Build.VERSION.SDK_INT < 20 && 308 | !((PowerManager) context.getApplicationContext() 309 | .getSystemService(Context.POWER_SERVICE)) 310 | .isScreenOn()) || (Build.VERSION.SDK_INT >= 20 && 311 | !APILevel20Wrapper.isScreenOn(context)))) { 312 | startTimer(context, TIMER_SCREEN_OFF, 313 | prefs.getInt("screen_off_timeout", TIMEOUT_SCREEN_OFF)); 314 | } 315 | } else if (intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 316 | WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_DISABLED) { 317 | Log.insert(context, R.string.event_disabled, Log.Type.WIFI_OFF); 318 | stopTimer(context, TIMER_SCREEN_OFF); 319 | stopTimer(context, TIMER_NO_NETWORK); 320 | } 321 | break; 322 | case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION: 323 | // wifi direct connection changed 324 | NetworkInfo nwi2 = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); 325 | WifiP2pInfo winfo = 326 | intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); 327 | if (BuildConfig.DEBUG) Logger.log("new P2P network state: " + nwi2.getState()); 328 | if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= 14) 329 | Logger.log("P2P group formed: " + APILevel14Wrapper.groupFormed(winfo)); 330 | if (nwi2.isConnected() || 331 | (Build.VERSION.SDK_INT >= 14 && APILevel14Wrapper.groupFormed(winfo))) { 332 | if (!nwi2.getState().equals(previousState)) { 333 | Log.insert(context, R.string.event_connected, Log.Type.WIFI_CONNECTED); 334 | } 335 | stopTimer(context, TIMER_NO_NETWORK); 336 | } else if (nwi2.getState().equals(NetworkInfo.State.DISCONNECTED) && 337 | !isWiFiConnected(context)) { 338 | if (!nwi2.getState().equals(previousState)) { 339 | Log.insert(context, R.string.event_disconnected, 340 | Log.Type.WIFI_DISCONNECTED); 341 | } 342 | if (prefs.getBoolean("off_no_network", true)) { 343 | startTimer(context, TIMER_NO_NETWORK, 344 | prefs.getInt("no_network_timeout", TIMEOUT_NO_NETWORK)); 345 | } 346 | } 347 | previousState = nwi2.getState(); 348 | break; 349 | case POWER_CONNECTED: 350 | case Intent.ACTION_POWER_CONNECTED: 351 | // connected to external power supply 352 | if (prefs.getBoolean("power_connected", false)) { 353 | Log.insert(context, R.string.event_ac, Log.Type.AC_CONNECTED); 354 | changeWiFi(context, true); 355 | if (prefs.getBoolean("off_screen_off", 356 | true)) { // ignore display off events while charging 357 | stopTimer(context, TIMER_SCREEN_OFF); 358 | prefs.edit().putBoolean("ignore_screen_off", true).apply(); 359 | if (BuildConfig.DEBUG) Logger.log("ignore screen off events"); 360 | } 361 | } 362 | break; 363 | case Intent.ACTION_POWER_DISCONNECTED: 364 | // disconnected from external power supply 365 | if (prefs.getBoolean("power_connected", false)) { 366 | Log.insert(context, R.string.event_ac_disconnected, 367 | Log.Type.AC_DISCONNECTED); 368 | // do we need to start the screen off timer? 369 | if (prefs.getBoolean("off_screen_off", true)) { 370 | prefs.edit().putBoolean("ignore_screen_off", false).apply(); 371 | if (BuildConfig.DEBUG) 372 | Logger.log("dont ignore screen off event any more"); 373 | if ((Build.VERSION.SDK_INT < 20 && 374 | !((PowerManager) context.getApplicationContext() 375 | .getSystemService(Context.POWER_SERVICE)) 376 | .isScreenOn()) || (Build.VERSION.SDK_INT >= 20 && 377 | !APILevel20Wrapper.isScreenOn(context))) { 378 | if (BuildConfig.DEBUG) Logger.log("screen is off -> start timer"); 379 | startTimer(context, TIMER_SCREEN_OFF, 380 | prefs.getInt("screen_off_timeout", TIMEOUT_SCREEN_OFF)); 381 | } 382 | } 383 | } 384 | break; 385 | } 386 | } 387 | } 388 | } 389 | --------------------------------------------------------------------------------