Settings: deviceinfo: Extend Battery info page
Change-Id: I5fcff258c878bd12d252321f269b89f3afa334ab Signed-off-by: Jyotiraditya Panda <jyotiraditya@aospa.co> Signed-off-by: Adithya R <gh0strider.2k18.reborn@gmail.com>
This commit is contained in:
committed by
Michael Bestas
parent
89224a355b
commit
72d0f90f30
@@ -154,4 +154,39 @@
|
||||
<string name="assisted_gps">Use assisted GPS</string>
|
||||
<!-- Location settings screen, setting summary for Assisted GPS switch -->
|
||||
<string name="assisted_gps_summary">Download satellite assistance data from the internet which can greatly improve the GPS startup performance. For emergency calls, assisted GPS is always allowed.</string>
|
||||
|
||||
<!-- Battery Info: Technology -->
|
||||
<string name="battery_technology">Technology</string>
|
||||
<string name="battery_technology_not_available" translatable="false">@string/battery_cycle_count_not_available</string>
|
||||
|
||||
<!-- Battery Info: Health -->
|
||||
<string name="battery_health">Health</string>
|
||||
<string name="battery_health_good">Good</string>
|
||||
<string name="battery_health_overheat">Overheat</string>
|
||||
<string name="battery_health_dead">Dead</string>
|
||||
<string name="battery_health_over_voltage">Over voltage</string>
|
||||
<string name="battery_health_unspecified_failure">Unspecified failure</string>
|
||||
<string name="battery_health_cold">Cold</string>
|
||||
<string name="battery_health_unknown">Unknown</string>
|
||||
|
||||
<!-- Battery Info: Temperature -->
|
||||
<string name="battery_temperature">Temperature</string>
|
||||
<string name="battery_temperature_not_available" translatable="false">@string/battery_cycle_count_not_available</string>
|
||||
|
||||
<!-- Battery Info: Voltage -->
|
||||
<string name="battery_voltage">Voltage</string>
|
||||
<string name="battery_voltage_not_available" translatable="false">@string/battery_cycle_count_not_available</string>
|
||||
|
||||
<!-- Battery Info: Charge Counter -->
|
||||
<string name="battery_charge_counter_summary">%1$d mAh</string>
|
||||
|
||||
<!-- Battery Info: Design Capacity -->
|
||||
<string name="battery_design_capacity">Design capacity</string>
|
||||
<string name="battery_design_capacity_summary">%1$d mAh</string>
|
||||
<string name="battery_design_capacity_not_available" translatable="false">@string/battery_cycle_count_not_available</string>
|
||||
|
||||
<!-- Battery Info: Maximum Capacity -->
|
||||
<string name="battery_maximum_capacity">Maximum capacity</string>
|
||||
<string name="battery_maximum_capacity_summary">%1$d mAh (%2$d%%)</string>
|
||||
<string name="battery_maximum_capacity_not_available" translatable="false">@string/battery_cycle_count_not_available</string>
|
||||
</resources>
|
||||
|
||||
@@ -21,6 +21,48 @@
|
||||
android:title="@string/battery_info"
|
||||
settings:keywords="@string/keywords_battery_info">
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_technology"
|
||||
android:title="@string/battery_technology"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryTechnologyPreferenceController"
|
||||
settings:enableCopying="true"/>
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_health"
|
||||
android:title="@string/battery_health"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryHealthPreferenceController"
|
||||
settings:enableCopying="true"/>
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_temperature"
|
||||
android:title="@string/battery_temperature"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryTemperaturePreferenceController"
|
||||
settings:enableCopying="true"/>
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_voltage"
|
||||
android:title="@string/battery_voltage"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryVoltagePreferenceController"
|
||||
settings:enableCopying="true"/>
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_design_capacity"
|
||||
android:title="@string/battery_design_capacity"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryDesignCapacityPreferenceController"
|
||||
settings:enableCopying="true"/>
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_maximum_capacity"
|
||||
android:title="@string/battery_maximum_capacity"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryMaximumCapacityPreferenceController"
|
||||
settings:enableCopying="true"/>
|
||||
|
||||
<Preference
|
||||
android:key="battery_info_manufacture_date"
|
||||
android:title="@string/battery_manufacture_date"
|
||||
|
||||
@@ -153,15 +153,6 @@
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:enableCopying="true"
|
||||
settings:controller="com.android.settings.deviceinfo.firmwareversion.LineageVersionDetailPreferenceController"/>
|
||||
|
||||
<!-- Battery information -->
|
||||
<Preference
|
||||
android:key="battery_info"
|
||||
android:order="44"
|
||||
android:title="@string/battery_info"
|
||||
android:fragment="com.android.settings.deviceinfo.batteryinfo.BatteryInfoFragment"
|
||||
settings:keywords="@string/keywords_battery_info"
|
||||
settings:controller="com.android.settings.deviceinfo.batteryinfo.BatteryInfoPreferenceController"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|
||||
@@ -95,6 +95,12 @@
|
||||
android:summary="@string/battery_percentage_description"
|
||||
settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />
|
||||
|
||||
<Preference
|
||||
android:key="battery_info"
|
||||
android:title="@string/battery_info"
|
||||
android:fragment="com.android.settings.deviceinfo.batteryinfo.BatteryInfoFragment"
|
||||
settings:keywords="@string/keywords_battery_info"/>
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="power_usage_footer"
|
||||
android:title="@string/battery_footer_summary"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deviceinfo.batteryinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.fuelgauge.BatteryUtils;
|
||||
|
||||
/**
|
||||
* A controller that manages the information about battery design capacity.
|
||||
*/
|
||||
public class BatteryDesignCapacityPreferenceController extends BasePreferenceController {
|
||||
|
||||
public BatteryDesignCapacityPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
Intent batteryIntent = BatteryUtils.getBatteryIntent(mContext);
|
||||
final int designCapacityUah =
|
||||
batteryIntent.getIntExtra(BatteryManager.EXTRA_DESIGN_CAPACITY, -1);
|
||||
|
||||
if (designCapacityUah != -1) {
|
||||
int designCapacity = designCapacityUah / 1_000;
|
||||
return mContext.getString(R.string.battery_design_capacity_summary, designCapacity);
|
||||
}
|
||||
|
||||
return mContext.getString(R.string.battery_design_capacity_not_available);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deviceinfo.batteryinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.fuelgauge.BatteryUtils;
|
||||
|
||||
/**
|
||||
* A controller that manages the information about battery health.
|
||||
*/
|
||||
public class BatteryHealthPreferenceController extends BasePreferenceController {
|
||||
|
||||
public BatteryHealthPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final Intent batteryIntent = BatteryUtils.getBatteryIntent(mContext);
|
||||
final int health =
|
||||
batteryIntent.getIntExtra(
|
||||
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
|
||||
|
||||
switch (health) {
|
||||
case BatteryManager.BATTERY_HEALTH_GOOD:
|
||||
return mContext.getString(R.string.battery_health_good);
|
||||
case BatteryManager.BATTERY_HEALTH_OVERHEAT:
|
||||
return mContext.getString(R.string.battery_health_overheat);
|
||||
case BatteryManager.BATTERY_HEALTH_DEAD:
|
||||
return mContext.getString(R.string.battery_health_dead);
|
||||
case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
|
||||
return mContext.getString(R.string.battery_health_over_voltage);
|
||||
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
|
||||
return mContext.getString(R.string.battery_health_unspecified_failure);
|
||||
case BatteryManager.BATTERY_HEALTH_COLD:
|
||||
return mContext.getString(R.string.battery_health_cold);
|
||||
default:
|
||||
return mContext.getString(R.string.battery_health_unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deviceinfo.batteryinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.fuelgauge.BatteryUtils;
|
||||
|
||||
/**
|
||||
* A controller that manages the information about battery maximum capacity.
|
||||
*/
|
||||
public class BatteryMaximumCapacityPreferenceController extends BasePreferenceController {
|
||||
|
||||
public BatteryMaximumCapacityPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
Intent batteryIntent = BatteryUtils.getBatteryIntent(mContext);
|
||||
final int maxCapacityUah =
|
||||
batteryIntent.getIntExtra(BatteryManager.EXTRA_MAXIMUM_CAPACITY, -1);
|
||||
final int designCapacityUah =
|
||||
batteryIntent.getIntExtra(BatteryManager.EXTRA_DESIGN_CAPACITY, -1);
|
||||
|
||||
if (maxCapacityUah != -1 && designCapacityUah != -1) {
|
||||
int maxCapacity = maxCapacityUah / 1_000;
|
||||
int designCapacity = designCapacityUah / 1_000;
|
||||
int percentage = (maxCapacity * 100) / designCapacity;
|
||||
|
||||
return mContext.getString(
|
||||
R.string.battery_maximum_capacity_summary, maxCapacity, percentage);
|
||||
}
|
||||
|
||||
return mContext.getString(R.string.battery_maximum_capacity_not_available);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deviceinfo.batteryinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.fuelgauge.BatteryUtils;
|
||||
|
||||
/**
|
||||
* A controller that manages the information about battery technology.
|
||||
*/
|
||||
public class BatteryTechnologyPreferenceController extends BasePreferenceController {
|
||||
|
||||
public BatteryTechnologyPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final Intent batteryIntent = BatteryUtils.getBatteryIntent(mContext);
|
||||
final String technology = batteryIntent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
|
||||
|
||||
return technology != null
|
||||
? technology
|
||||
: mContext.getText(R.string.battery_technology_not_available);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deviceinfo.batteryinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.icu.text.MeasureFormat;
|
||||
import android.icu.util.Measure;
|
||||
import android.icu.util.MeasureUnit;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.fuelgauge.BatteryUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A controller that manages the information about battery temperature.
|
||||
*/
|
||||
public class BatteryTemperaturePreferenceController extends BasePreferenceController {
|
||||
|
||||
public BatteryTemperaturePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final Intent batteryIntent = BatteryUtils.getBatteryIntent(mContext);
|
||||
final int temperatureTenths =
|
||||
batteryIntent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
|
||||
|
||||
if (temperatureTenths != -1) {
|
||||
float temperature = temperatureTenths / 10f;
|
||||
|
||||
return MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.SHORT)
|
||||
.format(new Measure(temperature, MeasureUnit.CELSIUS));
|
||||
}
|
||||
|
||||
return mContext.getText(R.string.battery_temperature_not_available);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deviceinfo.batteryinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.icu.text.MeasureFormat;
|
||||
import android.icu.util.Measure;
|
||||
import android.icu.util.MeasureUnit;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.fuelgauge.BatteryUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A controller that manages the information about battery voltage.
|
||||
*/
|
||||
public class BatteryVoltagePreferenceController extends BasePreferenceController {
|
||||
|
||||
public BatteryVoltagePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final Intent batteryIntent = BatteryUtils.getBatteryIntent(mContext);
|
||||
final int voltageMillivolts = batteryIntent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);
|
||||
|
||||
if (voltageMillivolts != -1) {
|
||||
float voltage = voltageMillivolts / 1_000f;
|
||||
|
||||
return MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.SHORT)
|
||||
.format(new Measure(voltage, MeasureUnit.VOLT));
|
||||
}
|
||||
|
||||
return mContext.getText(R.string.battery_voltage_not_available);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpd
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -31,6 +32,7 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.widget.UsageProgressBarPreference;
|
||||
|
||||
@@ -104,14 +106,28 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
Intent batteryBroadcast =
|
||||
com.android.settingslib.fuelgauge.BatteryUtils.getBatteryIntent(mContext);
|
||||
final int batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
|
||||
final boolean discharging =
|
||||
batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
|
||||
final int chargeCounterUah =
|
||||
batteryBroadcast.getIntExtra(BatteryManager.EXTRA_CHARGE_COUNTER, -1);
|
||||
|
||||
mBatteryUsageProgressBarPreference.setUsageSummary(
|
||||
formatBatteryPercentageText(batteryLevel));
|
||||
mBatteryUsageProgressBarPreference.setPercent(batteryLevel, BATTERY_MAX_LEVEL);
|
||||
|
||||
if (chargeCounterUah != -1) {
|
||||
int chargeCounter = chargeCounterUah / 1_000;
|
||||
mBatteryUsageProgressBarPreference.setTotalSummary(
|
||||
formatBatteryChargeCounterText(chargeCounter));
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence formatBatteryPercentageText(int batteryLevel) {
|
||||
return com.android.settings.Utils.formatPercentage(batteryLevel);
|
||||
}
|
||||
|
||||
private CharSequence formatBatteryChargeCounterText(int chargeCounter) {
|
||||
return mContext.getString(R.string.battery_charge_counter_summary, chargeCounter);
|
||||
}
|
||||
}
|
||||
// LINT.ThenChange(BatteryHeaderPreference.kt)
|
||||
|
||||
Reference in New Issue
Block a user