internal 包无法包含,形如"use of internal package internal/** not allowed "

本文详细介绍了如何处理在Go项目中遇到的useofinternalpackageinternal/**notallowed错误,通过调整项目的开发状态和修改VSCode设置文件,实现从应用开发切换到自身开发状态,有效解决了内部包无法包含的问题。

~、internal 包无法包含,形如"use of internal package internal/** not allowed "        
                //参 src/cmd/go/internal/load/pkg.go , disallowInternal() 

处理:将"应用开发"状态切换到internal包所属项目"自身开发"状态。

/devel/tmp4d/dev/go/go1.13/.vscode/settings.json :
{  
    "go.testEnvVars": {
        "GOPROXY":"https://goproxy.io",
        "GOROOT":"/devel/tmp4d/dev/go/go1.13",        //切换到gc编译器"项目自身开发"
        //"GOROOT":"/opt/go/go1.13",
        }
    "go.gopath": "/devel/tmp4d/dev/go/gopath",
}

/devel/tmp4d/dev/nsqio/.vscode/settings.json
{
    "go.gopath": "${workspaceRoot}:/opt/go/gopath",                //切换到该NSQ"项目自身开发"
    //"go.gopath": "/opt/go/gopath:${workspaceRoot}",
}
 

/** * Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential. * * Disclaimer * * Common: * Bosch Sensortec products are developed for the consumer goods industry. They may only be used * within the parameters of the respective valid product data sheet. Bosch Sensortec products are * provided with the express understanding that there is no warranty of fitness for a particular purpose. * They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device * that may lead to bodily harm or property damage if the system or device malfunctions. In addition, * Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems. * The resale and/or use of products are at the purchaser's own risk and his own responsibility. The * examination of fitness for the intended use is the sole responsibility of the Purchaser. * * The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for * incidental, or consequential damages, arising from any product use not covered by the parameters of * the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch * Sensortec for all costs in connection with such claims. * * The purchaser must monitor the market for the purchased products, particularly with regard to * product safety and inform Bosch Sensortec without delay of all security relevant incidents. * * Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid * technical specifications of the product series. They are therefore not intended or fit for resale to third * parties or for use in end products. Their sole purpose is internal client testing. The testing of an * engineering sample may in no way replace the testing of a product series. Bosch Sensortec * assumes no liability for the use of engineering samples. By accepting the engineering samples, the * Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering * samples. * * Special: * This software module (hereinafter called "Software") and any information on application-sheets * (hereinafter called "Information") is provided free of charge for the sole purpose to support your * application work. The Software and Information is subject to the following terms and conditions: * * The Software is specifically designed for the exclusive use for Bosch Sensortec products by * personnel who have special experience and training. Do not use this Software if you do not have the * proper experience or training. * * This Software package is provided `` as is `` and without any expressed or implied warranties, * including without limitation, the implied warranties of merchantability and fitness for a particular * purpose. * * Bosch Sensortec and their representatives and agents deny any liability for the functional impairment * of this Software in terms of fitness, performance and safety. Bosch Sensortec and their * representatives and agents shall not be liable for any direct or indirect damages or injury, except as * otherwise stipulated in mandatory applicable law. * * The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no * responsibility for the consequences of use of such Information nor for any infringement of patents or * other rights of third parties which may result from its use. No license is granted by implication or * otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are * subject to change without notice. * * It is not allowed to deliver the source code of the Software to any third party without permission of * Bosch Sensortec. * */ /*! * @file bsec_iot_example.c * * @brief * Example for using of BSEC library in a fixed configuration with the BME68x sensor. * This works by running an endless loop in the bsec_iot_loop() function. */ /*! * @addtogroup bsec_examples BSEC Examples * @brief BSEC usage examples * @{*/ /**********************************************************************************************************************/ /* header files */ /**********************************************************************************************************************/ #include "bsec_integration.h" /**********************************************************************************************************************/ /* functions */ /**********************************************************************************************************************/ /*! * @brief Write operation in either Wire or SPI * * param[in] reg_addr register address * param[in] reg_data_ptr pointer to the data to be written * param[in] data_len number of bytes to be written * param[in] intf_ptr interface pointer * * @return result of the bus communication function */ int8_t bus_write(uint8_t reg_addr, const uint8_t *reg_data_ptr, uint32_t data_len, void *intf_ptr) { // ... // Please insert system specific function to write to the bus where BME68x is connected // ... return 0; } /*! * @brief Read operation in either Wire or SPI * * param[in] reg_addr register address * param[out] reg_data_ptr pointer to the memory to be used to store the read data * param[in] data_len number of bytes to be read * param[in] intf_ptr interface pointer * * @return result of the bus communication function */ int8_t bus_read(uint8_t reg_addr, uint8_t *reg_data_ptr, uint32_t data_len, void *intf_ptr) { // ... // Please insert system specific function to read from bus where BME68x is connected // ... return 0; } /*! * @brief System specific implementation of sleep function * * @param[in] t_us Time in microseconds * @param[in] intf_ptr Pointer to the interface descriptor * * @return none */ void sleep_n(uint32_t t_us, void *intf_ptr) { // ... // Please insert system specific function sleep or delay for t_ms milliseconds // ... } /*! * @brief Capture the system time in microseconds * * @return system_current_time current system timestamp in microseconds */ int64_t get_timestamp_us() { int64_t system_current_time = 0; // ... // Please insert system specific function to retrieve a timestamp (in microseconds) // ... return system_current_time; } /*! * @brief Handling of the ready outputs * * @param[in] outputs output_t structure * @param[in] bsec_status value returned by the bsec_do_steps() call * * @return none */ void output_ready(output_t *outputs, bsec_library_return_t bsec_status) { // ... // Please insert system specific code to further process or display the BSEC outputs // ... } /*! * @brief Load previous library state from non-volatile memory * * @param[in,out] state_buffer buffer to hold the loaded state string * @param[in] n_buffer size of the allocated state buffer * * @return number of bytes copied to state_buffer */ uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer) { // ... // Load a previous library state from non-volatile memory, if available. // // Return zero if loading was unsuccessful or no state was available, // otherwise return length of loaded state string. // ... return 0; } /*! * @brief Save library state to non-volatile memory * * @param[in] state_buffer buffer holding the state to be stored * @param[in] length length of the state string to be stored * * @return none */ void state_save(const uint8_t *state_buffer, uint32_t length) { // ... // Save the string some form of non-volatile memory, if possible. // ... } /*! * @brief Load library config from non-volatile memory * * @param[in,out] config_buffer buffer to hold the loaded state string * @param[in] n_buffer size of the allocated state buffer * * @return number of bytes copied to config_buffer */ uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer) { // ... // Load a library config from non-volatile memory, if available. // // Return zero if loading was unsuccessful or no config was available, // otherwise return length of loaded config string. // ... return 0; } /*! * @brief Main function which configures BSEC library and then reads and processes the data from sensor based * on timer ticks * * @return result of the processing */ int main() { return_values_init ret; struct bme68x_dev bme_dev; memset(&bme_dev,0,sizeof(bme_dev)); /* Call to the function which initializes the BSEC library * Switch on low-power mode and provide no temperature offset */ ret = bsec_iot_init(BSEC_SAMPLE_RATE_LP, 0.0f, bus_write, bus_read, sleep_n, state_load, config_load, bme_dev, 0); if (ret.bme68x_status) { /* Could not intialize BME68x */ return (int)ret.bme68x_status; } else if (ret.bsec_status) { /* Could not intialize BSEC library */ return (int)ret.bsec_status; } /* Call to endless loop function which reads and processes data based on sensor settings */ /* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes */ bsec_iot_loop(sleep_n, get_timestamp_us, output_ready, state_save, 10000); return 0; } /*! @}*/ 根据这个例程使用stm32hal库用keil开发
07-25
请问如下代码有“状态值(如-1,0,1,2,3)是在读取和解析XML配置后,根据配置中的属性(如enabled和defaultDisplay)计算得出的”吗? /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.Display; import android.view.DisplayAddress; import android.view.DisplayInfo; import android.view.DisplayAddress; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.foldables.FoldGracePeriodProvider; import com.android.server.LocalServices; import com.android.server.display.feature.DisplayManagerFlags; import com.android.server.display.layout.DisplayIdProducer; import com.android.server.display.layout.Layout; import com.android.server.display.mode.SyntheticModeManager; import com.android.server.display.utils.DebugUtils; import com.android.server.policy.WindowManagerPolicy; import com.android.server.utils.FoldSettingProvider; import java.io.PrintWriter; import java.util.Arrays; import java.util.function.Consumer; /** * Responsible for creating {@link LogicalDisplay}s and associating them to the * {@link DisplayDevice} objects supplied through {@link DisplayAdapter.Listener}. * * Additionally this class will keep track of which {@link DisplayGroup} each * {@link LogicalDisplay} belongs to. * * For devices with a single internal display, the mapping is done once and left * alone. For devices with multiple built-in displays, such as foldable devices, * {@link LogicalDisplay}s can be remapped to different {@link DisplayDevice}s. */ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private static final String TAG = "LogicalDisplayMapper"; // To enable these logs, run: // 'adb shell setprop persist.log.tag.LogicalDisplayMapper DEBUG && adb reboot' private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1; public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2; public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3; public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4; public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5; public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6; public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 7; public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 8; public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 9; public static final int DISPLAY_GROUP_EVENT_ADDED = 1; public static final int DISPLAY_GROUP_EVENT_CHANGED = 2; public static final int DISPLAY_GROUP_EVENT_REMOVED = 3; private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500; private static final int MSG_TRANSITION_TO_PENDING_DEVICE_STATE = 1; private static final int UPDATE_STATE_NEW = 0; private static final int UPDATE_STATE_TRANSITION = 1; private static final int UPDATE_STATE_UPDATED = 2; private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1; /** * Temporary display info, used for comparing display configurations. */ private final DisplayInfo mTempDisplayInfo = new DisplayInfo(); private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo(); /** * True if the display mapper service should pretend there is only one display * and only tell applications about the existence of the default logical display. * The display manager can still mirror content to secondary displays but applications * cannot present unique content on those displays. * Used for demonstration purposes only. */ private final boolean mSingleDisplayDemoMode; /** * True if the device can have more than one internal display on at a time. */ private final boolean mSupportsConcurrentInternalDisplays; /** * Wake the device when transitioning into these device state. */ private final SparseBooleanArray mDeviceStatesOnWhichToWakeUp; /** * Sleep the device when transitioning into these device state. */ private final SparseBooleanArray mDeviceStatesOnWhichToSelectiveSleep; /** * Map of all logical displays indexed by logical display id. * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. * TODO: multi-display - Move the aforementioned comment? */ private final SparseArray<LogicalDisplay> mLogicalDisplays = new SparseArray<LogicalDisplay>(); private int mNextBuiltInDisplayId = 4096; // Cache whether or not the display was enabled on the last update. private final SparseBooleanArray mDisplaysEnabledCache = new SparseBooleanArray(); /** Map of all display groups indexed by display group id. */ private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>(); /** * Map of display groups which are linked to virtual devices (all displays in the group are * linked to that device). Keyed by virtual device unique id. */ private final SparseIntArray mDeviceDisplayGroupIds = new SparseIntArray(); /** * Map of display group ids indexed by display group name. */ private final ArrayMap<String, Integer> mDisplayGroupIdsByName = new ArrayMap<>(); private final DisplayDeviceRepository mDisplayDeviceRepo; private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; private final Listener mListener; private final DisplayManagerService.SyncRoot mSyncRoot; private final LogicalDisplayMapperHandler mHandler; private final FoldSettingProvider mFoldSettingProvider; private final FoldGracePeriodProvider mFoldGracePeriodProvider; private final PowerManager mPowerManager; /** * Has an entry for every logical display that the rest of the system has been notified about. * Any entry in here requires us to send a {@link LOGICAL_DISPLAY_EVENT_REMOVED} event when it * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed. The values are any * of the {@code UPDATE_STATE_*} constant types. */ private final SparseIntArray mUpdatedLogicalDisplays = new SparseIntArray(); /** * Keeps track of all the display groups that we already told other people about. IOW, if a * display group is in this array, then we *must* send change and remove notifications for it * because other components know about them. Also, what this array stores is a change counter * for each group, so we know if the group itself has changes since we last sent out a * notification. See {@link DisplayGroup#getChangeCountLocked}. */ private final SparseIntArray mUpdatedDisplayGroups = new SparseIntArray(); /** * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out. */ private final SparseIntArray mLogicalDisplaysToUpdate = new SparseIntArray(); /** * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out. */ private final SparseIntArray mDisplayGroupsToUpdate = new SparseIntArray(); /** * ArrayMap of display device unique ID to virtual device ID. Used in {@link * #updateLogicalDisplaysLocked} to establish which Virtual Devices own which Virtual Displays. */ private final ArrayMap<String, Integer> mVirtualDeviceDisplayMapping = new ArrayMap<>(); private WindowManagerPolicy mWindowManagerPolicy; private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; private final DisplayIdProducer mIdProducer = (isDefault) -> isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++; private Layout mCurrentLayout = null; private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; private int mDeviceStateToBeAppliedAfterBoot = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; private boolean mBootCompleted = false; private boolean mInteractive; private final DisplayManagerFlags mFlags; private final SyntheticModeManager mSyntheticModeManager; LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, FoldGracePeriodProvider foldGracePeriodProvider, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler, DisplayManagerFlags flags) { this(context, foldSettingProvider, foldGracePeriodProvider, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++, flags), flags, new SyntheticModeManager(flags)); } LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, FoldGracePeriodProvider foldGracePeriodProvider, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap, DisplayManagerFlags flags, SyntheticModeManager syntheticModeManager) { mSyncRoot = syncRoot; mPowerManager = context.getSystemService(PowerManager.class); mInteractive = mPowerManager.isInteractive(); mHandler = new LogicalDisplayMapperHandler(handler.getLooper()); mDisplayDeviceRepo = repo; mListener = listener; mFoldSettingProvider = foldSettingProvider; mFoldGracePeriodProvider = foldGracePeriodProvider; mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); mSupportsConcurrentInternalDisplays = context.getResources().getBoolean( com.android.internal.R.bool.config_supportsConcurrentInternalDisplays); mDeviceStatesOnWhichToWakeUp = toSparseBooleanArray(context.getResources().getIntArray( com.android.internal.R.array.config_deviceStatesOnWhichToWakeUp)); mDeviceStatesOnWhichToSelectiveSleep = toSparseBooleanArray( context.getResources().getIntArray( com.android.internal.R.array.config_deviceStatesOnWhichToSleep)); mDisplayDeviceRepo.addListener(this); mDeviceStateToLayoutMap = deviceStateToLayoutMap; mFlags = flags; mSyntheticModeManager = syntheticModeManager; } @Override public void onDisplayDeviceEventLocked(DisplayDevice device, int event) { switch (event) { case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED: if (DEBUG) { Slog.d(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); } handleDisplayDeviceAddedLocked(device); break; case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED: if (DEBUG) { Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); } handleDisplayDeviceRemovedLocked(device); updateLogicalDisplaysLocked(); break; } } @Override public void onDisplayDeviceChangedLocked(DisplayDevice device, int diff) { if (DEBUG) { Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); } finishStateTransitionLocked(false /*force*/); updateLogicalDisplaysLocked(diff); } @Override public void onTraversalRequested() { mListener.onTraversalRequested(); } public void onWindowManagerReady() { mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); } public LogicalDisplay getDisplayLocked(int displayId) { return getDisplayLocked(displayId, /* includeDisabled= */ true); } public LogicalDisplay getDisplayLocked(int displayId, boolean includeDisabled) { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display == null || display.isEnabledLocked() || includeDisabled) { return display; } return null; } public LogicalDisplay getDisplayLocked(DisplayDevice device) { return getDisplayLocked(device, /* includeDisabled= */ true); } public LogicalDisplay getDisplayLocked(DisplayDevice device, boolean includeDisabled) { if (device == null) { return null; } final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { final LogicalDisplay display = mLogicalDisplays.valueAt(i); if (display.getPrimaryDisplayDeviceLocked() == device) { if (display.isEnabledLocked() || includeDisabled) { return display; } return null; } } return null; } public int[] getDisplayIdsLocked(int callingUid, boolean includeDisabled) { final int count = mLogicalDisplays.size(); int[] displayIds = new int[count]; int n = 0; for (int i = 0; i < count; i++) { LogicalDisplay display = mLogicalDisplays.valueAt(i); if (display.isEnabledLocked() || includeDisabled) { DisplayInfo info = display.getDisplayInfoLocked(); if (info.hasAccess(callingUid)) { displayIds[n++] = mLogicalDisplays.keyAt(i); } } } if (n != count) { displayIds = Arrays.copyOfRange(displayIds, 0, n); } return displayIds; } public void forEachLocked(Consumer<LogicalDisplay> consumer) { forEachLocked(consumer, /* includeDisabled= */ true); } public void forEachLocked(Consumer<LogicalDisplay> consumer, boolean includeDisabled) { final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { LogicalDisplay display = mLogicalDisplays.valueAt(i); if (display.isEnabledLocked() || includeDisabled) { consumer.accept(display); } } } @VisibleForTesting public int getDisplayGroupIdFromDisplayIdLocked(int displayId) { final LogicalDisplay display = getDisplayLocked(displayId); if (display == null) { return Display.INVALID_DISPLAY_GROUP; } final int size = mDisplayGroups.size(); for (int i = 0; i < size; i++) { final DisplayGroup displayGroup = mDisplayGroups.valueAt(i); if (displayGroup.containsLocked(display)) { return mDisplayGroups.keyAt(i); } } return Display.INVALID_DISPLAY_GROUP; } public DisplayGroup getDisplayGroupLocked(int groupId) { return mDisplayGroups.get(groupId); } /** * Returns the {@link DisplayInfo} for this device state, indicated by the given display id. The * DisplayInfo represents the attributes of the indicated display in the layout associated with * this state. This is used to get display information for various displays in various states; * e.g. to help apps preload resources for the possible display states. * * @param deviceState the state to query possible layouts for * @param displayId the display id to retrieve * @return {@code null} if no corresponding {@link DisplayInfo} could be found, or the * {@link DisplayInfo} with a matching display id. */ @Nullable public DisplayInfo getDisplayInfoForStateLocked(int deviceState, int displayId) { // Retrieve the layout for this particular state. final Layout layout = mDeviceStateToLayoutMap.get(deviceState); if (layout == null) { // TODO(b/352019542): remove the log once b/345960547 is fixed. Slog.d(TAG, "Cannot get layout for given state:" + deviceState); return null; } // Retrieve the details of the given display within this layout. Layout.Display display = layout.getById(displayId); if (display == null) { // TODO(b/352019542): remove the log once b/345960547 is fixed. Slog.d(TAG, "Cannot get display for given layout:" + layout); return null; } // Retrieve the display info for the display that matches the display id. final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(display.getAddress()); if (device == null) { Slog.w(TAG, "The display device (" + display.getAddress() + "), is not available" + " for the display state " + mDeviceState); return null; } LogicalDisplay logicalDisplay = getDisplayLocked(device, /* includeDisabled= */ true); if (logicalDisplay == null) { Slog.w(TAG, "The logical display associated with address (" + display.getAddress() + "), is not available for the display state " + mDeviceState); return null; } DisplayInfo displayInfo = new DisplayInfo(logicalDisplay.getDisplayInfoLocked()); displayInfo.displayId = displayId; return displayInfo; } public void dumpLocked(PrintWriter pw) { pw.println("LogicalDisplayMapper:"); IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.increaseIndent(); ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); ipw.println("mCurrentLayout=" + mCurrentLayout); ipw.println("mDeviceStatesOnWhichToWakeUp=" + mDeviceStatesOnWhichToWakeUp); ipw.println("mDeviceStatesOnWhichSelectiveSleep=" + mDeviceStatesOnWhichToSelectiveSleep); ipw.println("mInteractive=" + mInteractive); ipw.println("mBootCompleted=" + mBootCompleted); ipw.println(); ipw.println("mDeviceState=" + mDeviceState); ipw.println("mPendingDeviceState=" + mPendingDeviceState); ipw.println("mDeviceStateToBeAppliedAfterBoot=" + mDeviceStateToBeAppliedAfterBoot); final int logicalDisplayCount = mLogicalDisplays.size(); ipw.println(); ipw.println("Logical Displays: size=" + logicalDisplayCount); for (int i = 0; i < logicalDisplayCount; i++) { int displayId = mLogicalDisplays.keyAt(i); LogicalDisplay display = mLogicalDisplays.valueAt(i); ipw.println("Display " + displayId + ":"); ipw.increaseIndent(); display.dumpLocked(ipw); ipw.decreaseIndent(); ipw.println(); } mDeviceStateToLayoutMap.dumpLocked(ipw); } /** * Creates an association between a displayDevice and a virtual device. Any displays associated * with this virtual device will be grouped together in a single {@link DisplayGroup} unless * created with {@link Display.FLAG_OWN_DISPLAY_GROUP}. * * @param displayDevice the displayDevice to be linked * @param virtualDeviceUniqueId the unique ID of the virtual device. */ void associateDisplayDeviceWithVirtualDevice( DisplayDevice displayDevice, int virtualDeviceUniqueId) { mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId); } void setDeviceStateLocked(int state) { if (!mBootCompleted) { // The boot animation might still be in progress, we do not want to switch states now // as the boot animation would end up with an incorrect size. if (DEBUG) { Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState + " until boot is completed"); } mDeviceStateToBeAppliedAfterBoot = state; return; } Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted); // As part of a state transition, we may need to turn off some displays temporarily so that // the transition is smooth. Plus, on some devices, only one internal displays can be // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be // temporarily turned off. resetLayoutLocked(mDeviceState, state, /* transitionValue= */ true); mPendingDeviceState = state; mDeviceStateToBeAppliedAfterBoot = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, mInteractive, mBootCompleted); final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, mInteractive, mBootCompleted); // If all displays are off already, we can just transition here, unless we are trying to // wake or sleep the device as part of this transition. In that case defer the final // transition until later once the device is awake/asleep. if (areAllTransitioningDisplaysOffLocked() && !wakeDevice && !sleepDevice) { transitionToPendingStateLocked(); return; } if (DEBUG) { Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState); } // Send the transitioning phase updates to DisplayManager so that the displays can // start turning OFF in preparation for the new layout. updateLogicalDisplaysLocked(); if (wakeDevice || sleepDevice) { if (wakeDevice) { // We already told the displays to turn off, now we need to wake the device as // we transition to this new state. We do it here so that the waking happens // between the transition from one layout to another. mHandler.post(() -> { mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_UNFOLD_DEVICE, "server.display:unfold"); }); } else if (sleepDevice) { // Send the device to sleep when required. int goToSleepFlag = mFoldSettingProvider.shouldSleepOnFold() ? 0 : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP; mHandler.post(() -> { mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD, goToSleepFlag); }); } } mHandler.sendEmptyMessageDelayed(MSG_TRANSITION_TO_PENDING_DEVICE_STATE, TIMEOUT_STATE_TRANSITION_MILLIS); } void onBootCompleted() { synchronized (mSyncRoot) { mBootCompleted = true; if (mDeviceStateToBeAppliedAfterBoot != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) { setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot); } } } void onEarlyInteractivityChange(boolean interactive) { synchronized (mSyncRoot) { if (mInteractive != interactive) { mInteractive = interactive; finishStateTransitionLocked(false /*force*/); } } } /** * Returns if the device should be woken up or not. Called to check if the device state we are * moving to is one that should awake the device, as well as if we are moving from a device * state that shouldn't have been already woken from. * * @param pendingState device state we are moving to * @param currentState device state we are currently in * @param isInteractive if the device is in an interactive state * @param isBootCompleted is the device fully booted * * @see #shouldDeviceBePutToSleep * @see #setDeviceStateLocked */ @VisibleForTesting boolean shouldDeviceBeWoken(int pendingState, int currentState, boolean isInteractive, boolean isBootCompleted) { return mDeviceStatesOnWhichToWakeUp.get(pendingState) && !mDeviceStatesOnWhichToWakeUp.get(currentState) && !isInteractive && isBootCompleted; } /** * Returns if the device should be put to sleep or not. * * Includes a check to verify that the device state that we are moving to, {@code pendingState}, * is the same as the physical state of the device, {@code baseState}. Also if the * 'Stay Awake On Fold' is not enabled. Different values for these parameters indicate a device * state override is active, and we shouldn't put the device to sleep to provide a better user * experience. * * @param pendingState device state we are moving to * @param currentState device state we are currently in * @param isInteractive if the device is in an interactive state * @param isBootCompleted is the device fully booted * * @see #shouldDeviceBeWoken * @see #setDeviceStateLocked */ @VisibleForTesting boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isInteractive, boolean isBootCompleted) { return currentState != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER && mDeviceStatesOnWhichToSelectiveSleep.get(pendingState) && !mDeviceStatesOnWhichToSelectiveSleep.get(currentState) && isInteractive && isBootCompleted && !mFoldSettingProvider.shouldStayAwakeOnFold(); } private boolean areAllTransitioningDisplaysOffLocked() { final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { final LogicalDisplay display = mLogicalDisplays.valueAt(i); if (!display.isInTransitionLocked()) { continue; } final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); if (device != null) { final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (info.state != Display.STATE_OFF) { return false; } } } return true; } private void transitionToPendingStateLocked() { resetLayoutLocked(mDeviceState, mPendingDeviceState, /* transitionValue= */ false); mDeviceState = mPendingDeviceState; mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; applyLayoutLocked(); updateLogicalDisplaysLocked(); } private void finishStateTransitionLocked(boolean force) { if (mPendingDeviceState == DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) { return; } final boolean waitingToWakeDevice = mDeviceStatesOnWhichToWakeUp.get(mPendingDeviceState) && !mDeviceStatesOnWhichToWakeUp.get(mDeviceState) && !mInteractive && mBootCompleted; // The device should only wait for sleep if #shouldStayAwakeOnFold method returns false. // If not, device should be marked ready for transition immediately. final boolean waitingToSleepDevice = mDeviceStatesOnWhichToSelectiveSleep.get( mPendingDeviceState) && !mDeviceStatesOnWhichToSelectiveSleep.get(mDeviceState) && mInteractive && mBootCompleted && !shouldStayAwakeOnFold(); final boolean displaysOff = areAllTransitioningDisplaysOffLocked(); final boolean isReadyToTransition = displaysOff && !waitingToWakeDevice && !waitingToSleepDevice; if (isReadyToTransition || force) { transitionToPendingStateLocked(); mHandler.removeMessages(MSG_TRANSITION_TO_PENDING_DEVICE_STATE); } else if (DEBUG) { Slog.d(TAG, "Not yet ready to transition to state=" + mPendingDeviceState + " with displays-off=" + displaysOff + ", force=" + force + ", mInteractive=" + mInteractive + ", isReady=" + isReadyToTransition); } } private void handleDisplayDeviceAddedLocked(DisplayDevice device) { DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); // The default Display needs to have additional initialization. // This initializes a default dynamic display layout for the default // device, which is used as a fallback in case no static layout definitions // exist or cannot be loaded. if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) { initializeDefaultDisplayDeviceLocked(device); } // Create a logical display for the new display device LogicalDisplay display = createNewLogicalDisplayLocked( device, mIdProducer.getId(/* isDefault= */ false)); applyLayoutLocked(); updateLogicalDisplaysLocked(); } private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); Layout.Display layoutDisplay = layout.getById(DEFAULT_DISPLAY); if (layoutDisplay == null) { return; } DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); // Remove any virtual device mapping which exists for the display. mVirtualDeviceDisplayMapping.remove(device.getUniqueId()); if (layoutDisplay.getAddress().equals(deviceInfo.address)) { layout.removeDisplayLocked(DEFAULT_DISPLAY); // Need to find another local display and make it default for (int i = 0; i < mLogicalDisplays.size(); i++) { LogicalDisplay nextDisplay = mLogicalDisplays.valueAt(i); DisplayDevice nextDevice = nextDisplay.getPrimaryDisplayDeviceLocked(); if (nextDevice == null) { continue; } DisplayDeviceInfo nextDeviceInfo = nextDevice.getDisplayDeviceInfoLocked(); if ((nextDeviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0 && !nextDeviceInfo.address.equals(deviceInfo.address)) { layout.createDefaultDisplayLocked(nextDeviceInfo.address, mIdProducer); applyLayoutLocked(); return; } } } } @VisibleForTesting void updateLogicalDisplays() { synchronized (mSyncRoot) { updateLogicalDisplaysLocked(); } } void updateLogicalDisplaysLocked() { updateLogicalDisplaysLocked(DisplayDeviceInfo.DIFF_EVERYTHING); } private void updateLogicalDisplaysLocked(int diff) { updateLogicalDisplaysLocked(diff, /* isSecondLoop= */ false); } /** * Updates the rest of the display system once all the changes are applied for display * devices and logical displays. The includes releasing invalid/empty LogicalDisplays, * creating/adjusting/removing DisplayGroups, and notifying the rest of the system of the * relevant changes. * * @param diff The DisplayDeviceInfo.DIFF_* of what actually changed to enable finer-grained * display update listeners * @param isSecondLoop If true, this is the second time this is called for the same change. */ private void updateLogicalDisplaysLocked(int diff, boolean isSecondLoop) { boolean reloop = false; // Go through all the displays and figure out if they need to be updated. // Loops in reverse so that displays can be removed during the loop without affecting the // rest of the loop. for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) { final int displayId = mLogicalDisplays.keyAt(i); LogicalDisplay display = mLogicalDisplays.valueAt(i); assignDisplayGroupLocked(display); boolean wasDirty = display.isDirtyLocked(); mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo); display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked(); final int updateState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW); final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW; final boolean wasPreviouslyEnabled = mDisplaysEnabledCache.get(displayId); final boolean isCurrentlyEnabled = display.isEnabledLocked(); // The display is no longer valid and needs to be removed. if (!display.isValidLocked()) { // Remove from group final DisplayGroup displayGroup = getDisplayGroupLocked( getDisplayGroupIdFromDisplayIdLocked(displayId)); if (displayGroup != null) { displayGroup.removeDisplayLocked(display); } if (wasPreviouslyUpdated) { // The display isn't actually removed from our internal data structures until // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}. if (mFlags.isConnectedDisplayManagementEnabled()) { if (mDisplaysEnabledCache.get(displayId)) { // We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED reloop = true; mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED); } else { mUpdatedLogicalDisplays.delete(displayId); mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_DISCONNECTED); } } else { mUpdatedLogicalDisplays.delete(displayId); mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED); } } else { // This display never left this class, safe to remove without notification mLogicalDisplays.removeAt(i); } continue; // The display is new. } else if (!wasPreviouslyUpdated) { if (mFlags.isConnectedDisplayManagementEnabled()) { // We still need to send LOGICAL_DISPLAY_EVENT_ADDED reloop = true; mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CONNECTED); } else { mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED); } // Underlying displays device has changed to a different one. } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) { mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED); // Something about the display device has changed. } else if (mFlags.isConnectedDisplayManagementEnabled() && wasPreviouslyEnabled != isCurrentlyEnabled) { int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED : LOGICAL_DISPLAY_EVENT_REMOVED; mLogicalDisplaysToUpdate.put(displayId, event); } else if (wasDirty || !mTempDisplayInfo.equals(newDisplayInfo)) { // If only the hdr/sdr ratio changed, then send just the event for that case if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) { mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED); } else { mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED); } // The display is involved in a display layout transition } else if (updateState == UPDATE_STATE_TRANSITION) { mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); // Display frame rate overrides changed. } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) { mLogicalDisplaysToUpdate.put( displayId, LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); // Non-override display values changed. } else { // While application shouldn't know nor care about the non-overridden info, we // still need to let WindowManager know so it can update its own internal state for // things like display cutouts. display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo); if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) { mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED); } } mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED); } // Go through the groups and do the same thing. We do this after displays since group // information can change in the previous loop. // Loops in reverse so that groups can be removed during the loop without affecting the // rest of the loop. for (int i = mDisplayGroups.size() - 1; i >= 0; i--) { final int groupId = mDisplayGroups.keyAt(i); final DisplayGroup group = mDisplayGroups.valueAt(i); final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) > -1; final int changeCount = group.getChangeCountLocked(); if (group.isEmptyLocked()) { mUpdatedDisplayGroups.delete(groupId); if (wasPreviouslyUpdated) { mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_REMOVED); } continue; } else if (!wasPreviouslyUpdated) { mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_ADDED); } else if (mUpdatedDisplayGroups.get(groupId) != changeCount) { mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_CHANGED); } mUpdatedDisplayGroups.put(groupId, changeCount); } // Send the display and display group updates in order by message type. This is important // to ensure that addition and removal notifications happen in the right order. sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED); if (mFlags.isConnectedDisplayManagementEnabled()) { sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED); } sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED); if (mFlags.isConnectedDisplayManagementEnabled()) { sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CONNECTED); } sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED); mLogicalDisplaysToUpdate.clear(); mDisplayGroupsToUpdate.clear(); if (reloop) { if (isSecondLoop) { Slog.wtf(TAG, "Trying to loop a third time"); return; } updateLogicalDisplaysLocked(diff, /* isSecondLoop= */ true); } } /** * Send the specified message for all relevant displays in the specified display-to-message map. */ private void sendUpdatesForDisplaysLocked(int msg) { for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) { final int currMsg = mLogicalDisplaysToUpdate.valueAt(i); if (currMsg != msg) { continue; } final int id = mLogicalDisplaysToUpdate.keyAt(i); final LogicalDisplay display = getDisplayLocked(id); if (DEBUG) { final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); final String uniqueId = device == null ? "null" : device.getUniqueId(); Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id + " with device=" + uniqueId); } if (mFlags.isConnectedDisplayManagementEnabled()) { if (msg == LOGICAL_DISPLAY_EVENT_ADDED) { mDisplaysEnabledCache.put(id, true); } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) { mDisplaysEnabledCache.delete(id); } } mListener.onLogicalDisplayEventLocked(display, msg); if (mFlags.isConnectedDisplayManagementEnabled()) { if (msg == LOGICAL_DISPLAY_EVENT_DISCONNECTED) { mLogicalDisplays.delete(id); } } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) { // We wait until we sent the EVENT_REMOVED event before actually removing the // display. mLogicalDisplays.delete(id); } } } /** * Send the specified message for all relevant display groups in the specified message map. */ private void sendUpdatesForGroupsLocked(int msg) { for (int i = mDisplayGroupsToUpdate.size() - 1; i >= 0; --i) { final int currMsg = mDisplayGroupsToUpdate.valueAt(i); if (currMsg != msg) { continue; } final int id = mDisplayGroupsToUpdate.keyAt(i); mListener.onDisplayGroupEventLocked(id, msg); if (msg == DISPLAY_GROUP_EVENT_REMOVED) { // We wait until we sent the EVENT_REMOVED event before actually removing the // group. mDisplayGroups.delete(id); // Remove possible reference to the removed group. int deviceIndex = mDeviceDisplayGroupIds.indexOfValue(id); if (deviceIndex >= 0) { mDeviceDisplayGroupIds.removeAt(deviceIndex); } } } } /** This method should be called before LogicalDisplay.updateLocked, * DisplayInfo in LogicalDisplay (display.getDisplayInfoLocked()) is not updated yet, * and should not be used directly or indirectly in this method */ private void assignDisplayGroupLocked(LogicalDisplay display) { if (!display.isValidLocked()) { // null check for display.mPrimaryDisplayDevice return; } // updated primary device directly from LogicalDisplay (not from DisplayInfo) final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked(); // final in LogicalDisplay final int displayId = display.getDisplayIdLocked(); final String primaryDisplayUniqueId = displayDevice.getUniqueId(); final Integer linkedDeviceUniqueId = mVirtualDeviceDisplayMapping.get(primaryDisplayUniqueId); // Get current display group data int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); Integer deviceDisplayGroupId = null; if (linkedDeviceUniqueId != null && mDeviceDisplayGroupIds.indexOfKey(linkedDeviceUniqueId) > 0) { deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); } final DisplayGroup oldGroup = getDisplayGroupLocked(groupId); // groupName directly from LogicalDisplay (not from DisplayInfo) final String groupName = display.getDisplayGroupNameLocked(); // DisplayDeviceInfo is safe to use, it is updated earlier final DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); // Get the new display group if a change is needed, if display group name is empty and // {@code DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP} is not set, the display is assigned // to the default display group. final boolean needsOwnDisplayGroup = (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0 || !TextUtils.isEmpty(groupName); final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP; final boolean needsDeviceDisplayGroup = !needsOwnDisplayGroup && linkedDeviceUniqueId != null; final boolean hasDeviceDisplayGroup = deviceDisplayGroupId != null && groupId == deviceDisplayGroupId; if (groupId == Display.INVALID_DISPLAY_GROUP || hasOwnDisplayGroup != needsOwnDisplayGroup || hasDeviceDisplayGroup != needsDeviceDisplayGroup) { groupId = assignDisplayGroupIdLocked(needsOwnDisplayGroup, display.getDisplayGroupNameLocked(), needsDeviceDisplayGroup, linkedDeviceUniqueId); } // Create a new group if needed DisplayGroup newGroup = getDisplayGroupLocked(groupId); if (newGroup == null) { newGroup = new DisplayGroup(groupId); mDisplayGroups.append(groupId, newGroup); } if (oldGroup != newGroup) { if (oldGroup != null) { oldGroup.removeDisplayLocked(display); } newGroup.addDisplayLocked(display); display.updateDisplayGroupIdLocked(groupId); Slog.i(TAG, "Setting new display group " + groupId + " for display " + displayId + ", from previous group: " + (oldGroup != null ? oldGroup.getGroupId() : "null")); } } /** * Goes through all the displays used in the layouts for the specified {@code fromState} and * {@code toState} and un/marks them for transition. When a new layout is requested, we * mark the displays that will change into a transitional phase so that they can all be turned * OFF. Once all are confirmed OFF, then this method gets called again to reset transition * marker. This helps to ensure that all display-OFF requests are made before * display-ON which in turn hides any resizing-jank windows might incur when switching displays. * * @param fromState The state we are switching from. * @param toState The state we are switching to. * @param transitionValue The value to mark the transition state: true == transitioning. */ private void resetLayoutLocked(int fromState, int toState, boolean transitionValue) { final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState); final Layout toLayout = mDeviceStateToLayoutMap.get(toState); final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { final LogicalDisplay logicalDisplay = mLogicalDisplays.valueAt(i); final int displayId = logicalDisplay.getDisplayIdLocked(); final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked(); if (device == null) { // If there's no device, then the logical display is due to be removed. Ignore it. continue; } // Grab the display associations this display-device has in the old layout and the // new layout. final DisplayAddress address = device.getDisplayDeviceInfoLocked().address; // Virtual displays do not have addresses, so account for nulls. final Layout.Display fromDisplay = address != null ? fromLayout.getByAddress(address) : null; final Layout.Display toDisplay = address != null ? toLayout.getByAddress(address) : null; // If the display is in one of the layouts but not the other, then the content will // change, so in this case we also want to blank the displays to avoid jank. final boolean displayNotInBothLayouts = (fromDisplay == null) != (toDisplay == null); // If a layout doesn't mention a display-device at all, then the display-device defaults // to enabled. This is why we treat null as "enabled" in the code below. final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled(); final boolean willBeEnabled = toDisplay == null || toDisplay.isEnabled(); final boolean deviceHasNewLogicalDisplayId = fromDisplay != null && toDisplay != null && fromDisplay.getLogicalDisplayId() != toDisplay.getLogicalDisplayId(); // We consider a display-device as changing/transition if // 1) It's already marked as transitioning // 2) It's going from enabled to disabled, or vice versa // 3) It's enabled, but it's mapped to a new logical display ID. To the user this // would look like apps moving from one screen to another since task-stacks stay // with the logical display [ID]. // 4) It's in one layout but not the other, so the content will change. final boolean isTransitioning = logicalDisplay.isInTransitionLocked() || (wasEnabled != willBeEnabled) || deviceHasNewLogicalDisplayId || displayNotInBothLayouts; if (isTransitioning) { if (transitionValue != logicalDisplay.isInTransitionLocked()) { Slog.i(TAG, "Set isInTransition on display " + displayId + ": " + transitionValue); } // This will either mark the display as "transitioning" if we are starting to change // the device state, or remove the transitioning marker if the state change is // ending. logicalDisplay.setIsInTransitionLocked(transitionValue); mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION); } } } /** * Apply (or reapply) the currently selected display layout. */ private void applyLayoutLocked() { final Layout oldLayout = mCurrentLayout; mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState); Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout); // Go through each of the displays in the current layout set. final int size = mCurrentLayout.size(); for (int i = 0; i < size; i++) { final Layout.Display displayLayout = mCurrentLayout.getAt(i); // If the underlying display-device we want to use for this display // doesn't exist, then skip it. This can happen at startup as display-devices // trickle in one at a time. When the new display finally shows up, the layout is // recalculated so that the display is properly added to the current layout. final DisplayAddress address = displayLayout.getAddress(); final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address); if (device == null) { Slog.w(TAG, "applyLayoutLocked: The display device (" + address + "), is not " + "available for the display state " + mDeviceState); continue; } // Now that we have a display-device, we need a LogicalDisplay to map it to. Find the // right one, if it doesn't exist, create a new one. final int logicalDisplayId = displayLayout.getLogicalDisplayId(); LogicalDisplay newDisplay = getDisplayLocked(logicalDisplayId); boolean newDisplayCreated = false; if (newDisplay == null) { newDisplay = createNewLogicalDisplayLocked( null /*displayDevice*/, logicalDisplayId); newDisplayCreated = true; } // Now swap the underlying display devices between the old display and the new display final LogicalDisplay oldDisplay = getDisplayLocked(device); if (newDisplay != oldDisplay) { // Display is swapping, notify WindowManager, so it can prepare for // the display switch if (!newDisplayCreated && mWindowManagerPolicy != null) { mWindowManagerPolicy.onDisplaySwitchStart(newDisplay.getDisplayIdLocked()); } newDisplay.swapDisplaysLocked(oldDisplay); } DisplayDeviceConfig config = device.getDisplayDeviceConfig(); newDisplay.setDevicePositionLocked(displayLayout.getPosition()); newDisplay.setLeadDisplayLocked(displayLayout.getLeadDisplayId()); newDisplay.updateLayoutLimitedRefreshRateLocked( config.getRefreshRange(displayLayout.getRefreshRateZoneId()) ); newDisplay.updateThermalRefreshRateThrottling( config.getThermalRefreshRateThrottlingData( displayLayout.getRefreshRateThermalThrottlingMapId() ) ); setEnabledLocked(newDisplay, displayLayout.isEnabled()); newDisplay.setThermalBrightnessThrottlingDataIdLocked( displayLayout.getThermalBrightnessThrottlingMapId() == null ? DisplayDeviceConfig.DEFAULT_ID : displayLayout.getThermalBrightnessThrottlingMapId()); newDisplay.setPowerThrottlingDataIdLocked( displayLayout.getPowerThrottlingMapId() == null ? DisplayDeviceConfig.DEFAULT_ID : displayLayout.getPowerThrottlingMapId()); newDisplay.setDisplayGroupNameLocked(displayLayout.getDisplayGroupName()); } } /** * Creates a new logical display for the specified device and display Id and adds it to the list * of logical displays. * * @param device The device to associate with the LogicalDisplay. * @param displayId The display ID to give the new display. If invalid, a new ID is assigned. * @return The new logical display if created, null otherwise. */ private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) { final int layerStack = assignLayerStackLocked(displayId); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled(), mFlags.isAlwaysRotateDisplayDeviceEnabled()); display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); final DisplayInfo info = display.getDisplayInfoLocked(); if (info.type == Display.TYPE_INTERNAL && mDeviceStateToLayoutMap.size() > 1) { // If this is an internal display and the device uses a display layout configuration, // the display should be disabled as later we will receive a device state update, which // will tell us which internal displays should be enabled and which should be disabled. display.setEnabledLocked(false); } mLogicalDisplays.put(displayId, display); return display; } void setEnabledLocked(LogicalDisplay display, boolean isEnabled) { final int displayId = display.getDisplayIdLocked(); final DisplayInfo info = display.getDisplayInfoLocked(); final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode && (info.type != Display.TYPE_INTERNAL); if (isEnabled && disallowSecondaryDisplay) { Slog.i(TAG, "Not creating a logical display for a secondary display because single" + " display demo mode is enabled: " + display.getDisplayInfoLocked()); isEnabled = false; } if (display.isEnabledLocked() != isEnabled) { Slog.i(TAG, "SetEnabled on display " + displayId + ": " + isEnabled); display.setEnabledLocked(isEnabled); } } private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup, String displayGroupName, boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId) { if (isDeviceDisplayGroup && linkedDeviceUniqueId != null) { int deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); // A value of 0 indicates that no device display group was found. if (deviceDisplayGroupId == 0) { deviceDisplayGroupId = mNextNonDefaultGroupId++; mDeviceDisplayGroupIds.put(linkedDeviceUniqueId, deviceDisplayGroupId); } return deviceDisplayGroupId; } if (!isOwnDisplayGroup) return Display.DEFAULT_DISPLAY_GROUP; Integer displayGroupId = mDisplayGroupIdsByName.get(displayGroupName); if (displayGroupId == null) { displayGroupId = Integer.valueOf(mNextNonDefaultGroupId++); mDisplayGroupIdsByName.put(displayGroupName, displayGroupId); } return displayGroupId; } private void initializeDefaultDisplayDeviceLocked(DisplayDevice device) { // We always want to make sure that our default layout creates a logical // display for the default display device that is found. // To that end, when we are notified of a new default display, we add it to // the default layout definition if it is not already there. final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); if (layout.getById(DEFAULT_DISPLAY) != null) { // The layout should only have one default display return; } final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); layout.createDefaultDisplayLocked(info.address, mIdProducer); } private int assignLayerStackLocked(int displayId) { // Currently layer stacks and display ids are the same. // This need not be the case. return displayId; } private SparseBooleanArray toSparseBooleanArray(int[] input) { final SparseBooleanArray retval = new SparseBooleanArray(2); for (int i = 0; input != null && i < input.length; i++) { retval.put(input[i], true); } return retval; } /** * Returns true if the device would definitely have outer display ON/Stay Awake on fold based on * the value of `Continue using app on fold` setting */ private boolean shouldStayAwakeOnFold() { return mFoldSettingProvider.shouldStayAwakeOnFold() || ( mFoldSettingProvider.shouldSelectiveStayAwakeOnFold() && mFoldGracePeriodProvider.isEnabled()); } private String displayEventToString(int msg) { switch(msg) { case LOGICAL_DISPLAY_EVENT_ADDED: return "added"; case LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION: return "transition"; case LOGICAL_DISPLAY_EVENT_CHANGED: return "changed"; case LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED: return "framerate_override"; case LOGICAL_DISPLAY_EVENT_SWAPPED: return "swapped"; case LOGICAL_DISPLAY_EVENT_REMOVED: return "removed"; case LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED: return "hdr_sdr_ratio_changed"; case LOGICAL_DISPLAY_EVENT_CONNECTED: return "connected"; case LOGICAL_DISPLAY_EVENT_DISCONNECTED: return "disconnected"; } return null; } void setDisplayEnabledLocked(@NonNull LogicalDisplay display, boolean enabled) { boolean isEnabled = display.isEnabledLocked(); if (isEnabled == enabled) { Slog.w(TAG, "Display is already " + (isEnabled ? "enabled" : "disabled") + ": " + display.getDisplayIdLocked()); return; } setEnabledLocked(display, enabled); updateLogicalDisplaysLocked(); } public interface Listener { void onLogicalDisplayEventLocked(LogicalDisplay display, int event); void onDisplayGroupEventLocked(int groupId, int event); void onTraversalRequested(); } private class LogicalDisplayMapperHandler extends Handler { LogicalDisplayMapperHandler(Looper looper) { super(looper, null, true /*async*/); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_TRANSITION_TO_PENDING_DEVICE_STATE: synchronized (mSyncRoot) { finishStateTransitionLocked(true /*force*/); } break; } } } }
最新发布
10-25
第五步:编辑 buildozer.spec 文件 打开 buildozer.spec 文件,修改以下内容:我把我原始的给你,你直接给我全部修改完输出全代码,我目前的全代码是[app] # (str) Title of your application title = My Kivy App # (str) Package name package.name = mykivyapp # (str) Package domain (needed for android/ios packaging) package.domain = org.test # (str) Source code where the main.py live source.dir = . # (str) Main filename source.filename = 1.py # (list) Source files to include (let empty to include all the files) source.include_exts = py,png,jpg,kv,atlas # (list) List of inclusions using pattern matching #source.include_patterns = assets/*,images/*.png # (list) Source files to exclude (let empty to not exclude anything) #source.exclude_exts = spec # (list) List of directory to exclude (let empty to not exclude anything) #source.exclude_dirs = tests, bin, venv # (list) Exclusions using pattern matching #source.exclude_patterns = license,images/*/*.jpg # (str) Application versioning (method 1) version = 0.1 # (str) Application versioning (method 2) # version.regex = __version__ = ['"](.*)['"] # version.filename = %(source.dir)s/main.py # (list) Application requirements # comma separated e.g. requirements = sqlite3,kivy requirements = python3,kivy,requests,numpy # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes # requirements.source.kivy = ../../kivy # (str) Presplash of the application #presplash.filename = %(source.dir)s/data/presplash.png # (str) Icon of the application #icon.filename = %(source.dir)s/data/icon.png # (list) Supported orientations # Valid options are: landscape, portrait, portrait-reverse or landscape-reverse orientation = portrait # (list) List of service to declare #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY # # OSX Specific # # # author = © Copyright Info # change the major version of python used by the app osx.python_version = 3 # Kivy version to use osx.kivy_version = 1.9.1 # # Android specific # # (bool) Indicate if the application should be fullscreen or not fullscreen = 0 # (string) Presplash background color (for android toolchain) # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, # olive, purple, silver, teal. #android.presplash_color = #FFFFFF # (string) Presplash animation using Lottie format. # see https://lottiefiles.com/ for examples and https://airbnb.design/lottie/ # for general documentation. # Lottie files can be created using various tools, like Adobe After Effect or Synfig. #android.presplash_lottie = "path/to/lottie/file.json" # (str) Adaptive icon of the application (used if Android API level is 26+ at runtime) #icon.adaptive_foreground.filename = %(source.dir)s/data/icon_fg.png #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png # (list) Permissions # (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties) #android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18) # (list) features (adds uses-feature -tags to manifest) #android.features = android.hardware.usb.host # (int) Target Android API, should be as high as possible. #android.api = 31 # (int) Minimum API your APK / AAB will support. #android.minapi = 21 # (str) Android SDK version to use #android.sdk = 20 # (str) Android NDK version to use #android.ndk = 23b # (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi. #android.ndk_api = 21 # (bool) Use --private data storage (True) or --dir public storage (False) #android.private_storage = True # (str) Android NDK directory (if empty, it will be automatically downloaded.) #android.ndk_path = # (str) Android SDK directory (if empty, it will be automatically downloaded.) #android.sdk_path = # (str) ANT directory (if empty, it will be automatically downloaded.) #android.ant_path = # (bool) If True, then skip trying to update the Android sdk # This can be useful to avoid excess Internet downloads or save time # when an update is due and you just want to test/build your package # android.skip_update = False # (bool) If True, then automatically accept SDK license # agreements. This is intended for automation only. If set to False, # the default, you will be shown the license when first running # buildozer. # android.accept_sdk_license = False # (str) Android entry point, default is ok for Kivy-based app #android.entrypoint = org.kivy.android.PythonActivity # (str) Full name including package path of the Java class that implements Android Activity # use that parameter together with android.entrypoint to set custom Java class instead of PythonActivity #android.activity_class_name = org.kivy.android.PythonActivity # (str) Extra xml to write directly inside the <manifest> element of AndroidManifest.xml # use that parameter to provide a filename from where to load your custom XML code #android.extra_manifest_xml = ./src/android/extra_manifest.xml # (str) Extra xml to write directly inside the <manifest><application> tag of AndroidManifest.xml # use that parameter to provide a filename from where to load your custom XML arguments: #android.extra_manifest_application_arguments = ./src/android/extra_manifest_application_arguments.xml # (str) Full name including package path of the Java class that implements Python Service # use that parameter to set custom Java class which extends PythonService #android.service_class_name = org.kivy.android.PythonService # (str) Android app theme, default is ok for Kivy-based app # android.apptheme = "@android:style/Theme.NoTitleBar" # (list) Pattern to whitelist for the whole project #android.whitelist = # (str) Path to a custom whitelist file #android.whitelist_src = # (str) Path to a custom blacklist file #android.blacklist_src = # (list) List of Java .jar files to add to the libs so that pyjnius can access # their classes. Don't add jars that you do not need, since extra jars can slow # down the build process. Allows wildcards matching, for example: # OUYA-ODK/libs/*.jar #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar # (list) List of Java files to add to the android project (can be java or a # directory containing the files) #android.add_src = # (list) Android AAR archives to add #android.add_aars = # (list) Put these files or directories in the apk assets directory. # Either form may be used, and assets need not be in 'source.include_exts'. # 1) android.add_assets = source_asset_relative_path # 2) android.add_assets = source_asset_path:destination_asset_relative_path #android.add_assets = # (list) Put these files or directories in the apk res directory. # The option may be used in three ways, the value may contain one or zero ':' # Some examples: # 1) A file to add to resources, legal resource names contain ['a-z','0-9','_'] # android.add_resources = my_icons/all-inclusive.png:drawable/all_inclusive.png # 2) A directory, here 'legal_icons' must contain resources of one kind # android.add_resources = legal_icons:drawable # 3) A directory, here 'legal_resources' must contain one or more directories, # each of a resource kind: drawable, xml, etc... # android.add_resources = legal_resources # (list) Gradle dependencies to add #android.gradle_dependencies = # (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' # contains an 'androidx' package, or any package from Kotlin source. # android.enable_androidx requires android.api >= 28 #android.enable_androidx = True # (list) add java compile options # this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option # see https://developer.android.com/studio/write/java8-support for further information # android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8" # (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies} # please enclose in double quotes # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }" #android.add_gradle_repositories = # (list) packaging options to add # see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html # can be necessary to solve conflicts in gradle_dependencies # please enclose in double quotes # e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'" #android.add_packaging_options = # (list) Java classes to add as activities to the manifest. #android.add_activities = com.example.ExampleActivity # (str) OUYA Console category. Should be one of GAME or APP # If you leave this blank, OUYA support will not be enabled #android.ouya.category = GAME # (str) Filename of OUYA Console icon. It must be a 732x412 png image. #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png # (str) XML file to include as an intent filters in <activity> tag #android.manifest.intent_filters = # (list) Copy these files to src/main/res/xml/ (used for example with intent-filters) #android.res_xml = PATH_TO_FILE, # (str) launchMode to set for the main activity #android.manifest.launch_mode = standard # (str) screenOrientation to set for the main activity. # Valid values can be found at https://developer.android.com/guide/topics/manifest/activity-element #android.manifest.orientation = fullSensor # (list) Android additional libraries to copy into libs/armeabi #android.add_libs_armeabi = libs/android/*.so #android.add_libs_armeabi_v7a = libs/android-v7/*.so #android.add_libs_arm64_v8a = libs/android-v8/*.so #android.add_libs_x86 = libs/android-x86/*.so #android.add_libs_mips = libs/android-mips/*.so # (bool) Indicate whether the screen should stay on # Don't forget to add the WAKE_LOCK permission if you set this to True #android.wakelock = False # (list) Android application meta-data to set (key=value format) #android.meta_data = # (list) Android library project to add (will be added in the # project.properties automatically.) #android.library_references = # (list) Android shared libraries which will be added to AndroidManifest.xml using <uses-library> tag #android.uses_library = # (str) Android logcat filters to use #android.logcat_filters = *:S python:D # (bool) Android logcat only display log for activity's pid #android.logcat_pid_only = False # (str) Android additional adb arguments #android.adb_args = -H host.docker.internal # (bool) Copy library instead of making a libpymodules.so #android.copy_libs = 1 # (list) The Android archs to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64 android.archs = arm64-v8a, armeabi-v7a # (int) overrides automatic versionCode computation (used in build.gradle) # this is not the same as app version and should only be edited if you know what you're doing # android.numeric_version = 1 # (bool) enables Android auto backup feature (Android API >=23) android.allow_backup = True # (str) XML file for custom backup rules (see official auto backup documentation) # android.backup_rules = # (str) If you need to insert variables into your AndroidManifest.xml file, # you can do so with the manifestPlaceholders property. # This property takes a map of key-value pairs. (via a string) # Usage example : android.manifest_placeholders = [myCustomUrl:\"org.kivy.customurl\"] # android.manifest_placeholders = [:] # (bool) Skip byte compile for .py files # android.no-byte-compile-python = False # (str) The format used to package the app for release mode (aab or apk or aar). # android.release_artifact = aab # (str) The format used to package the app for debug mode (apk or aar). # android.debug_artifact = apk # # Python for android (p4a) specific # # (str) python-for-android URL to use for checkout #p4a.url = # (str) python-for-android fork to use in case if p4a.url is not specified, defaults to upstream (kivy) #p4a.fork = kivy # (str) python-for-android branch to use, defaults to master #p4a.branch = master # (str) python-for-android specific commit to use, defaults to HEAD, must be within p4a.branch #p4a.commit = HEAD # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) #p4a.source_dir = # (str) The directory in which python-for-android should look for your own build recipes (if any) #p4a.local_recipes = # (str) Filename to the hook for p4a #p4a.hook = # (str) Bootstrap to use for android builds # p4a.bootstrap = sdl2 # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) #p4a.port = # Control passing the --use-setup-py vs --ignore-setup-py to p4a # "in the future" --use-setup-py is going to be the default behaviour in p4a, right now it is not # Setting this to false will pass --ignore-setup-py, true will pass --use-setup-py # NOTE: this is general setuptools integration, having pyproject.toml is enough, no need to generate # setup.py if you're using Poetry, but you need to add "toml" to source.include_exts. #p4a.setup_py = false # (str) extra command line arguments to pass when invoking pythonforandroid.toolchain #p4a.extra_args = # # iOS specific # # (str) Path to a custom kivy-ios folder #ios.kivy_ios_dir = ../kivy-ios # Alternately, specify the URL and branch of a git checkout: ios.kivy_ios_url = https://github.com/kivy/kivy-ios ios.kivy_ios_branch = master # Another platform dependency: ios-deploy # Uncomment to use a custom checkout #ios.ios_deploy_dir = ../ios_deploy # Or specify URL and branch ios.ios_deploy_url = https://github.com/phonegap/ios-deploy ios.ios_deploy_branch = 1.10.0 # (bool) Whether or not to sign the code ios.codesign.allowed = false # (str) Name of the certificate to use for signing the debug version # Get a list of available identities: buildozer ios list_identities #ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)" # (str) The development team to use for signing the debug version #ios.codesign.development_team.debug = <hexstring> # (str) Name of the certificate to use for signing the release version #ios.codesign.release = %(ios.codesign.debug)s # (str) The development team to use for signing the release version #ios.codesign.development_team.release = <hexstring> # (str) URL pointing to .ipa file to be installed # This option should be defined along with `display_image_url` and `full_size_image_url` options. #ios.manifest.app_url = # (str) URL pointing to an icon (57x57px) to be displayed during download # This option should be defined along with `app_url` and `full_size_image_url` options. #ios.manifest.display_image_url = # (str) URL pointing to a large icon (512x512px) to be used by iTunes # This option should be defined along with `app_url` and `display_image_url` options. #ios.manifest.full_size_image_url = [buildozer] # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) log_level = 2 # (int) Display warning if buildozer is run as root (0 = False, 1 = True) warn_on_root = 1 # (str) Path to build artifact storage, absolute or relative to spec file # build_dir = ./.buildozer # (str) Path to build output (i.e. .apk, .aab, .ipa) storage # bin_dir = ./bin # ----------------------------------------------------------------------------- # List as sections # # You can define all the "list" as [section:key]. # Each line will be considered as a option to the list. # Let's take [app] / source.exclude_patterns. # Instead of doing: # #[app] #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* # # This can be translated into: # #[app:source.exclude_patterns] #license #data/audio/*.wav #data/images/original/* # # ----------------------------------------------------------------------------- # Profiles # # You can extend section / key with a profile # For example, you want to deploy a demo version of your application without # HD content. You could first change the title to add "(demo)" in the name # and extend the excluded directories to remove the HD content. # #[app@demo] #title = My Application (demo) # #[app:source.exclude_patterns@demo] #images/hd/* # # Then, invoke the command line with the "demo" profile: # #buildozer --profile demo android debug
09-03
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值