如何根据白天或夜晚更改背景图片 android
how to change a background image depending on whether it is day or night android
我想知道如何在我的 android 应用程序中根据白天或晚上更改背景图片。
独立打开应用程序,只取决于是晚上还是白天。
谢谢!
有两种方法可以做到这一点
使用手机上可用的光传感器。
使用手机时间。
Calendar c = Calendar.getInstance();
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
if(timeOfDay >= 0 && timeOfDay < 12){
Toast.makeText(this, "Good Morning", Toast.LENGTH_SHORT).show();
}else if(timeOfDay >= 12 && timeOfDay < 16){
Toast.makeText(this, "Good Afternoon", Toast.LENGTH_SHORT).show();
}else if(timeOfDay >= 16 && timeOfDay < 21){
Toast.makeText(this, "Good Evening", Toast.LENGTH_SHORT).show();
}else if(timeOfDay >= 21 && timeOfDay < 24){
Toast.makeText(this, "Good Night", Toast.LENGTH_SHORT).show();
}
尝试用 AM/PM 获取您 Android 的当前时间,
Calendar now = Calendar.getInstance();
int a = now.get(Calendar.AM_PM);
if(a == Calendar.AM)
System.out.println("AM"+now.get(Calendar.HOUR));
现在再次检查时间以设置白天和黑夜,例如,如果 8:00 下午是晚上,如果 10:00 上午是白天。
当您的应用程序打开时,然后调用以下函数:
Calendar c = Calendar.getInstance();
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
if(timeOfDay >= 0 && timeOfDay < 12){
view.setBackground(R.mipmap.img1);
}else if(timeOfDay >= 12 && timeOfDay < 16){
view.setBackground(R.mipmap.img2);
}else if(timeOfDay >= 16 && timeOfDay < 21){
view.setBackground(R.mipmap.img3);
}else if(timeOfDay >= 21 && timeOfDay < 24){
view.setBackground(R.mipmap.img4);
}
或
如果你想改变闪屏背景那么你需要把上面的代码片段放在应用程序 class
public class ApplicationController 扩展应用程序 {
@Override
public void onCreate() {
super.onCreate();
Calendar c = Calendar.getInstance();
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
if(timeOfDay >= 0 && timeOfDay < 12){
Global.drawable = getResources().getDrawable(R.mipmap.img1)
}else if(timeOfDay >= 12 && timeOfDay < 16){
Global.drawable = getResources().getDrawable(R.mipmap.img2)
}else if(timeOfDay >= 16 && timeOfDay < 21){
Global.drawable = getResources().getDrawable(R.mipmap.img3)
}else if(timeOfDay >= 21 && timeOfDay < 24){
Global.drawable = getResources().getDrawable(R.mipmap.img4)
}
}
}
使用Global.drawable作为闪屏背景。
清单:
<application
android:name=".ApplicationController"
当前时间并不能真正告诉您是晚上还是白天,因为在世界上不同的地方(取决于 north/south 您的情况)您将在不同的时间进入夜晚。
不仅如此,一年四季,日落和日出的时间每天都在变化。
您需要做的是首先获取设备的位置(或至少是它的估计值),然后进行一些计算。
Google 最近发布 (here) 它的代码可用但已弃用(因为性能不佳)。它实际上用于与您写的相同的目的:根据现在是否是晚上设置 dark/light 主题。
用法:
private void updateUi(Location location) {
if (location != null) {
TwilightCalculator twilightCalculator = TwilightCalculator.getInstance();
twilightCalculator.calculateTwilight(System.currentTimeMillis(), location.getLatitude(), location.getLongitude());
boolean isDay = twilightCalculator.state == TwilightCalculator.DAY;
locationTv.setText("Latitude : " + location.getLatitude() + "\nLongitude : " + location.getLongitude() + "\nIsDay?" + isDay);
}
}
代码
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.appcompat.app;
import android.text.format.DateUtils;
/**
* Imported from frameworks/base/services/core/java/com/android/server/TwilightCalculator.java
*
* <p>Calculates the sunrise and sunsets times for a given location.</p>
*/
class TwilightCalculator {
private static TwilightCalculator sInstance;
static TwilightCalculator getInstance() {
if (sInstance == null) {
sInstance = new TwilightCalculator();
}
return sInstance;
}
/** Value of {@link #state} if it is currently day */
public static final int DAY = 0;
/** Value of {@link #state} if it is currently night */
public static final int NIGHT = 1;
private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f);
// element for calculating solar transit.
private static final float J0 = 0.0009f;
// correction for civil twilight
@SuppressWarnings("FloatingPointLiteralPrecision")
private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f;
// coefficients for calculating Equation of Center.
private static final float C1 = 0.0334196f;
private static final float C2 = 0.000349066f;
private static final float C3 = 0.000005236f;
@SuppressWarnings("FloatingPointLiteralPrecision")
private static final float OBLIQUITY = 0.40927971f;
// Java time on Jan 1, 2000 12:00 UTC.
private static final long UTC_2000 = 946728000000L;
/**
* Time of sunset (civil twilight) in milliseconds or -1 in the case the day
* or night never ends.
*/
public long sunset;
/**
* Time of sunrise (civil twilight) in milliseconds or -1 in the case the
* day or night never ends.
*/
public long sunrise;
/**
* Current state
*/
public int state;
/**
* calculates the civil twilight bases on time and geo-coordinates.
*
* @param time time in milliseconds.
* @param latitude latitude in degrees.
* @param longitude latitude in degrees.
*/
@SuppressWarnings("FloatingPointLiteralPrecision")
public void calculateTwilight(long time, double latitude, double longitude) {
final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS;
// mean anomaly
final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
// true anomaly
final double trueAnomaly = meanAnomaly + C1 * Math.sin(meanAnomaly) + C2
* Math.sin(2 * meanAnomaly) + C3 * Math.sin(3 * meanAnomaly);
// ecliptic longitude
final double solarLng = trueAnomaly + 1.796593063d + Math.PI;
// solar transit in days since 2000
final double arcLongitude = -longitude / 360;
float n = Math.round(daysSince2000 - J0 - arcLongitude);
double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053d * Math.sin(meanAnomaly)
+ -0.0069d * Math.sin(2 * solarLng);
// declination of sun
double solarDec = Math.asin(Math.sin(solarLng) * Math.sin(OBLIQUITY));
final double latRad = latitude * DEGREES_TO_RADIANS;
double cosHourAngle = (Math.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
* Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
// The day or night never ends for the given date and location, if this value is out of
// range.
if (cosHourAngle >= 1) {
state = NIGHT;
sunset = -1;
sunrise = -1;
return;
} else if (cosHourAngle <= -1) {
state = DAY;
sunset = -1;
sunrise = -1;
return;
}
float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI));
sunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
sunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
if (sunrise < time && sunset > time) {
state = DAY;
} else {
state = NIGHT;
}
}
}
平台:
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.twilight;
import android.annotation.NonNull;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.icu.impl.CalendarAstronomer;
import android.icu.util.Calendar;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
import java.util.Objects;
/**
* Figures out whether it's twilight time based on the user's location.
* <p>
* Used by the UI mode manager and other components to adjust night mode
* effects based on sunrise and sunset.
*/
public final class TwilightService extends SystemService
implements AlarmManager.OnAlarmListener, Handler.Callback, LocationListener {
private static final String TAG = "TwilightService";
private static final boolean DEBUG = false;
private static final int MSG_START_LISTENING = 1;
private static final int MSG_STOP_LISTENING = 2;
@GuardedBy("mListeners")
private final ArrayMap<TwilightListener, Handler> mListeners = new ArrayMap<>();
private final Handler mHandler;
protected AlarmManager mAlarmManager;
private LocationManager mLocationManager;
private boolean mBootCompleted;
private boolean mHasListeners;
private BroadcastReceiver mTimeChangedReceiver;
protected Location mLastLocation;
@GuardedBy("mListeners")
protected TwilightState mLastTwilightState;
public TwilightService(Context context) {
super(context);
mHandler = new Handler(Looper.getMainLooper(), this);
}
@Override
public void onStart() {
publishLocalService(TwilightManager.class, new TwilightManager() {
@Override
public void registerListener(@NonNull TwilightListener listener,
@NonNull Handler handler) {
synchronized (mListeners) {
final boolean wasEmpty = mListeners.isEmpty();
mListeners.put(listener, handler);
if (wasEmpty && !mListeners.isEmpty()) {
mHandler.sendEmptyMessage(MSG_START_LISTENING);
}
}
}
@Override
public void unregisterListener(@NonNull TwilightListener listener) {
synchronized (mListeners) {
final boolean wasEmpty = mListeners.isEmpty();
mListeners.remove(listener);
if (!wasEmpty && mListeners.isEmpty()) {
mHandler.sendEmptyMessage(MSG_STOP_LISTENING);
}
}
}
@Override
public TwilightState getLastTwilightState() {
synchronized (mListeners) {
return mLastTwilightState;
}
}
});
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
final Context c = getContext();
mAlarmManager = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
mLocationManager = (LocationManager) c.getSystemService(Context.LOCATION_SERVICE);
mBootCompleted = true;
if (mHasListeners) {
startListening();
}
}
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_START_LISTENING:
if (!mHasListeners) {
mHasListeners = true;
if (mBootCompleted) {
startListening();
}
}
return true;
case MSG_STOP_LISTENING:
if (mHasListeners) {
mHasListeners = false;
if (mBootCompleted) {
stopListening();
}
}
return true;
}
return false;
}
private void startListening() {
Slog.d(TAG, "startListening");
// Start listening for location updates (default: low power, max 1h, min 10m).
mLocationManager.requestLocationUpdates(
null /* default */, this, Looper.getMainLooper());
// Request the device's location immediately if a previous location isn't available.
if (mLocationManager.getLastLocation() == null) {
if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
mLocationManager.requestSingleUpdate(
LocationManager.NETWORK_PROVIDER, this, Looper.getMainLooper());
} else if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
mLocationManager.requestSingleUpdate(
LocationManager.GPS_PROVIDER, this, Looper.getMainLooper());
}
}
// Update whenever the system clock is changed.
if (mTimeChangedReceiver == null) {
mTimeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Slog.d(TAG, "onReceive: " + intent);
updateTwilightState();
}
};
final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
}
// Force an update now that we have listeners registered.
updateTwilightState();
}
private void stopListening() {
Slog.d(TAG, "stopListening");
if (mTimeChangedReceiver != null) {
getContext().unregisterReceiver(mTimeChangedReceiver);
mTimeChangedReceiver = null;
}
if (mLastTwilightState != null) {
mAlarmManager.cancel(this);
}
mLocationManager.removeUpdates(this);
mLastLocation = null;
}
private void updateTwilightState() {
// Calculate the twilight state based on the current time and location.
final long currentTimeMillis = System.currentTimeMillis();
final Location location = mLastLocation != null ? mLastLocation
: mLocationManager.getLastLocation();
final TwilightState state = calculateTwilightState(location, currentTimeMillis);
if (DEBUG) {
Slog.d(TAG, "updateTwilightState: " + state);
}
// Notify listeners if the state has changed.
synchronized (mListeners) {
if (!Objects.equals(mLastTwilightState, state)) {
mLastTwilightState = state;
for (int i = mListeners.size() - 1; i >= 0; --i) {
final TwilightListener listener = mListeners.keyAt(i);
final Handler handler = mListeners.valueAt(i);
handler.post(new Runnable() {
@Override
public void run() {
listener.onTwilightStateChanged(state);
}
});
}
}
}
// Schedule an alarm to update the state at the next sunrise or sunset.
if (state != null) {
final long triggerAtMillis = state.isNight()
? state.sunriseTimeMillis() : state.sunsetTimeMillis();
mAlarmManager.setExact(AlarmManager.RTC, triggerAtMillis, TAG, this, mHandler);
}
}
@Override
public void onAlarm() {
Slog.d(TAG, "onAlarm");
updateTwilightState();
}
@Override
public void onLocationChanged(Location location) {
// Location providers may erroneously return (0.0, 0.0) when they fail to determine the
// device's location. These location updates can be safely ignored since the chance of a
// user actually being at these coordinates is quite low.
if (location != null
&& !(location.getLongitude() == 0.0 && location.getLatitude() == 0.0)) {
Slog.d(TAG, "onLocationChanged:"
+ " provider=" + location.getProvider()
+ " accuracy=" + location.getAccuracy()
+ " time=" + location.getTime());
mLastLocation = location;
updateTwilightState();
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
/**
* Calculates the twilight state for a specific location and time.
*
* @param location the location to use
* @param timeMillis the reference time to use
* @return the calculated {@link TwilightState}, or {@code null} if location is {@code null}
*/
private static TwilightState calculateTwilightState(Location location, long timeMillis) {
if (location == null) {
return null;
}
final CalendarAstronomer ca = new CalendarAstronomer(
location.getLongitude(), location.getLatitude());
final Calendar noon = Calendar.getInstance();
noon.setTimeInMillis(timeMillis);
noon.set(Calendar.HOUR_OF_DAY, 12);
noon.set(Calendar.MINUTE, 0);
noon.set(Calendar.SECOND, 0);
noon.set(Calendar.MILLISECOND, 0);
ca.setTime(noon.getTimeInMillis());
long sunriseTimeMillis = ca.getSunRiseSet(true /* rise */);
long sunsetTimeMillis = ca.getSunRiseSet(false /* rise */);
if (sunsetTimeMillis < timeMillis) {
noon.add(Calendar.DATE, 1);
ca.setTime(noon.getTimeInMillis());
sunriseTimeMillis = ca.getSunRiseSet(true /* rise */);
} else if (sunriseTimeMillis > timeMillis) {
noon.add(Calendar.DATE, -1);
ca.setTime(noon.getTimeInMillis());
sunsetTimeMillis = ca.getSunRiseSet(false /* rise */);
}
return new TwilightState(sunriseTimeMillis, sunsetTimeMillis);
}
}
我想知道如何在我的 android 应用程序中根据白天或晚上更改背景图片。
独立打开应用程序,只取决于是晚上还是白天。
谢谢!
有两种方法可以做到这一点
使用手机上可用的光传感器。
使用手机时间。
Calendar c = Calendar.getInstance(); int timeOfDay = c.get(Calendar.HOUR_OF_DAY); if(timeOfDay >= 0 && timeOfDay < 12){ Toast.makeText(this, "Good Morning", Toast.LENGTH_SHORT).show(); }else if(timeOfDay >= 12 && timeOfDay < 16){ Toast.makeText(this, "Good Afternoon", Toast.LENGTH_SHORT).show(); }else if(timeOfDay >= 16 && timeOfDay < 21){ Toast.makeText(this, "Good Evening", Toast.LENGTH_SHORT).show(); }else if(timeOfDay >= 21 && timeOfDay < 24){ Toast.makeText(this, "Good Night", Toast.LENGTH_SHORT).show(); }
尝试用 AM/PM 获取您 Android 的当前时间,
Calendar now = Calendar.getInstance();
int a = now.get(Calendar.AM_PM);
if(a == Calendar.AM)
System.out.println("AM"+now.get(Calendar.HOUR));
现在再次检查时间以设置白天和黑夜,例如,如果 8:00 下午是晚上,如果 10:00 上午是白天。
当您的应用程序打开时,然后调用以下函数:
Calendar c = Calendar.getInstance();
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
if(timeOfDay >= 0 && timeOfDay < 12){
view.setBackground(R.mipmap.img1);
}else if(timeOfDay >= 12 && timeOfDay < 16){
view.setBackground(R.mipmap.img2);
}else if(timeOfDay >= 16 && timeOfDay < 21){
view.setBackground(R.mipmap.img3);
}else if(timeOfDay >= 21 && timeOfDay < 24){
view.setBackground(R.mipmap.img4);
}
或
如果你想改变闪屏背景那么你需要把上面的代码片段放在应用程序 class
public class ApplicationController 扩展应用程序 {
@Override
public void onCreate() {
super.onCreate();
Calendar c = Calendar.getInstance();
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
if(timeOfDay >= 0 && timeOfDay < 12){
Global.drawable = getResources().getDrawable(R.mipmap.img1)
}else if(timeOfDay >= 12 && timeOfDay < 16){
Global.drawable = getResources().getDrawable(R.mipmap.img2)
}else if(timeOfDay >= 16 && timeOfDay < 21){
Global.drawable = getResources().getDrawable(R.mipmap.img3)
}else if(timeOfDay >= 21 && timeOfDay < 24){
Global.drawable = getResources().getDrawable(R.mipmap.img4)
}
}
}
使用Global.drawable作为闪屏背景。 清单:
<application
android:name=".ApplicationController"
当前时间并不能真正告诉您是晚上还是白天,因为在世界上不同的地方(取决于 north/south 您的情况)您将在不同的时间进入夜晚。 不仅如此,一年四季,日落和日出的时间每天都在变化。
您需要做的是首先获取设备的位置(或至少是它的估计值),然后进行一些计算。
Google 最近发布 (here) 它的代码可用但已弃用(因为性能不佳)。它实际上用于与您写的相同的目的:根据现在是否是晚上设置 dark/light 主题。
用法:
private void updateUi(Location location) {
if (location != null) {
TwilightCalculator twilightCalculator = TwilightCalculator.getInstance();
twilightCalculator.calculateTwilight(System.currentTimeMillis(), location.getLatitude(), location.getLongitude());
boolean isDay = twilightCalculator.state == TwilightCalculator.DAY;
locationTv.setText("Latitude : " + location.getLatitude() + "\nLongitude : " + location.getLongitude() + "\nIsDay?" + isDay);
}
}
代码
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.appcompat.app;
import android.text.format.DateUtils;
/**
* Imported from frameworks/base/services/core/java/com/android/server/TwilightCalculator.java
*
* <p>Calculates the sunrise and sunsets times for a given location.</p>
*/
class TwilightCalculator {
private static TwilightCalculator sInstance;
static TwilightCalculator getInstance() {
if (sInstance == null) {
sInstance = new TwilightCalculator();
}
return sInstance;
}
/** Value of {@link #state} if it is currently day */
public static final int DAY = 0;
/** Value of {@link #state} if it is currently night */
public static final int NIGHT = 1;
private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f);
// element for calculating solar transit.
private static final float J0 = 0.0009f;
// correction for civil twilight
@SuppressWarnings("FloatingPointLiteralPrecision")
private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f;
// coefficients for calculating Equation of Center.
private static final float C1 = 0.0334196f;
private static final float C2 = 0.000349066f;
private static final float C3 = 0.000005236f;
@SuppressWarnings("FloatingPointLiteralPrecision")
private static final float OBLIQUITY = 0.40927971f;
// Java time on Jan 1, 2000 12:00 UTC.
private static final long UTC_2000 = 946728000000L;
/**
* Time of sunset (civil twilight) in milliseconds or -1 in the case the day
* or night never ends.
*/
public long sunset;
/**
* Time of sunrise (civil twilight) in milliseconds or -1 in the case the
* day or night never ends.
*/
public long sunrise;
/**
* Current state
*/
public int state;
/**
* calculates the civil twilight bases on time and geo-coordinates.
*
* @param time time in milliseconds.
* @param latitude latitude in degrees.
* @param longitude latitude in degrees.
*/
@SuppressWarnings("FloatingPointLiteralPrecision")
public void calculateTwilight(long time, double latitude, double longitude) {
final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS;
// mean anomaly
final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
// true anomaly
final double trueAnomaly = meanAnomaly + C1 * Math.sin(meanAnomaly) + C2
* Math.sin(2 * meanAnomaly) + C3 * Math.sin(3 * meanAnomaly);
// ecliptic longitude
final double solarLng = trueAnomaly + 1.796593063d + Math.PI;
// solar transit in days since 2000
final double arcLongitude = -longitude / 360;
float n = Math.round(daysSince2000 - J0 - arcLongitude);
double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053d * Math.sin(meanAnomaly)
+ -0.0069d * Math.sin(2 * solarLng);
// declination of sun
double solarDec = Math.asin(Math.sin(solarLng) * Math.sin(OBLIQUITY));
final double latRad = latitude * DEGREES_TO_RADIANS;
double cosHourAngle = (Math.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
* Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
// The day or night never ends for the given date and location, if this value is out of
// range.
if (cosHourAngle >= 1) {
state = NIGHT;
sunset = -1;
sunrise = -1;
return;
} else if (cosHourAngle <= -1) {
state = DAY;
sunset = -1;
sunrise = -1;
return;
}
float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI));
sunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
sunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
if (sunrise < time && sunset > time) {
state = DAY;
} else {
state = NIGHT;
}
}
}
平台:
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.twilight;
import android.annotation.NonNull;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.icu.impl.CalendarAstronomer;
import android.icu.util.Calendar;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
import java.util.Objects;
/**
* Figures out whether it's twilight time based on the user's location.
* <p>
* Used by the UI mode manager and other components to adjust night mode
* effects based on sunrise and sunset.
*/
public final class TwilightService extends SystemService
implements AlarmManager.OnAlarmListener, Handler.Callback, LocationListener {
private static final String TAG = "TwilightService";
private static final boolean DEBUG = false;
private static final int MSG_START_LISTENING = 1;
private static final int MSG_STOP_LISTENING = 2;
@GuardedBy("mListeners")
private final ArrayMap<TwilightListener, Handler> mListeners = new ArrayMap<>();
private final Handler mHandler;
protected AlarmManager mAlarmManager;
private LocationManager mLocationManager;
private boolean mBootCompleted;
private boolean mHasListeners;
private BroadcastReceiver mTimeChangedReceiver;
protected Location mLastLocation;
@GuardedBy("mListeners")
protected TwilightState mLastTwilightState;
public TwilightService(Context context) {
super(context);
mHandler = new Handler(Looper.getMainLooper(), this);
}
@Override
public void onStart() {
publishLocalService(TwilightManager.class, new TwilightManager() {
@Override
public void registerListener(@NonNull TwilightListener listener,
@NonNull Handler handler) {
synchronized (mListeners) {
final boolean wasEmpty = mListeners.isEmpty();
mListeners.put(listener, handler);
if (wasEmpty && !mListeners.isEmpty()) {
mHandler.sendEmptyMessage(MSG_START_LISTENING);
}
}
}
@Override
public void unregisterListener(@NonNull TwilightListener listener) {
synchronized (mListeners) {
final boolean wasEmpty = mListeners.isEmpty();
mListeners.remove(listener);
if (!wasEmpty && mListeners.isEmpty()) {
mHandler.sendEmptyMessage(MSG_STOP_LISTENING);
}
}
}
@Override
public TwilightState getLastTwilightState() {
synchronized (mListeners) {
return mLastTwilightState;
}
}
});
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
final Context c = getContext();
mAlarmManager = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
mLocationManager = (LocationManager) c.getSystemService(Context.LOCATION_SERVICE);
mBootCompleted = true;
if (mHasListeners) {
startListening();
}
}
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_START_LISTENING:
if (!mHasListeners) {
mHasListeners = true;
if (mBootCompleted) {
startListening();
}
}
return true;
case MSG_STOP_LISTENING:
if (mHasListeners) {
mHasListeners = false;
if (mBootCompleted) {
stopListening();
}
}
return true;
}
return false;
}
private void startListening() {
Slog.d(TAG, "startListening");
// Start listening for location updates (default: low power, max 1h, min 10m).
mLocationManager.requestLocationUpdates(
null /* default */, this, Looper.getMainLooper());
// Request the device's location immediately if a previous location isn't available.
if (mLocationManager.getLastLocation() == null) {
if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
mLocationManager.requestSingleUpdate(
LocationManager.NETWORK_PROVIDER, this, Looper.getMainLooper());
} else if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
mLocationManager.requestSingleUpdate(
LocationManager.GPS_PROVIDER, this, Looper.getMainLooper());
}
}
// Update whenever the system clock is changed.
if (mTimeChangedReceiver == null) {
mTimeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Slog.d(TAG, "onReceive: " + intent);
updateTwilightState();
}
};
final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
}
// Force an update now that we have listeners registered.
updateTwilightState();
}
private void stopListening() {
Slog.d(TAG, "stopListening");
if (mTimeChangedReceiver != null) {
getContext().unregisterReceiver(mTimeChangedReceiver);
mTimeChangedReceiver = null;
}
if (mLastTwilightState != null) {
mAlarmManager.cancel(this);
}
mLocationManager.removeUpdates(this);
mLastLocation = null;
}
private void updateTwilightState() {
// Calculate the twilight state based on the current time and location.
final long currentTimeMillis = System.currentTimeMillis();
final Location location = mLastLocation != null ? mLastLocation
: mLocationManager.getLastLocation();
final TwilightState state = calculateTwilightState(location, currentTimeMillis);
if (DEBUG) {
Slog.d(TAG, "updateTwilightState: " + state);
}
// Notify listeners if the state has changed.
synchronized (mListeners) {
if (!Objects.equals(mLastTwilightState, state)) {
mLastTwilightState = state;
for (int i = mListeners.size() - 1; i >= 0; --i) {
final TwilightListener listener = mListeners.keyAt(i);
final Handler handler = mListeners.valueAt(i);
handler.post(new Runnable() {
@Override
public void run() {
listener.onTwilightStateChanged(state);
}
});
}
}
}
// Schedule an alarm to update the state at the next sunrise or sunset.
if (state != null) {
final long triggerAtMillis = state.isNight()
? state.sunriseTimeMillis() : state.sunsetTimeMillis();
mAlarmManager.setExact(AlarmManager.RTC, triggerAtMillis, TAG, this, mHandler);
}
}
@Override
public void onAlarm() {
Slog.d(TAG, "onAlarm");
updateTwilightState();
}
@Override
public void onLocationChanged(Location location) {
// Location providers may erroneously return (0.0, 0.0) when they fail to determine the
// device's location. These location updates can be safely ignored since the chance of a
// user actually being at these coordinates is quite low.
if (location != null
&& !(location.getLongitude() == 0.0 && location.getLatitude() == 0.0)) {
Slog.d(TAG, "onLocationChanged:"
+ " provider=" + location.getProvider()
+ " accuracy=" + location.getAccuracy()
+ " time=" + location.getTime());
mLastLocation = location;
updateTwilightState();
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
/**
* Calculates the twilight state for a specific location and time.
*
* @param location the location to use
* @param timeMillis the reference time to use
* @return the calculated {@link TwilightState}, or {@code null} if location is {@code null}
*/
private static TwilightState calculateTwilightState(Location location, long timeMillis) {
if (location == null) {
return null;
}
final CalendarAstronomer ca = new CalendarAstronomer(
location.getLongitude(), location.getLatitude());
final Calendar noon = Calendar.getInstance();
noon.setTimeInMillis(timeMillis);
noon.set(Calendar.HOUR_OF_DAY, 12);
noon.set(Calendar.MINUTE, 0);
noon.set(Calendar.SECOND, 0);
noon.set(Calendar.MILLISECOND, 0);
ca.setTime(noon.getTimeInMillis());
long sunriseTimeMillis = ca.getSunRiseSet(true /* rise */);
long sunsetTimeMillis = ca.getSunRiseSet(false /* rise */);
if (sunsetTimeMillis < timeMillis) {
noon.add(Calendar.DATE, 1);
ca.setTime(noon.getTimeInMillis());
sunriseTimeMillis = ca.getSunRiseSet(true /* rise */);
} else if (sunriseTimeMillis > timeMillis) {
noon.add(Calendar.DATE, -1);
ca.setTime(noon.getTimeInMillis());
sunsetTimeMillis = ca.getSunRiseSet(false /* rise */);
}
return new TwilightState(sunriseTimeMillis, sunsetTimeMillis);
}
}