diff options
Diffstat (limited to 'services')
13 files changed, 392 insertions, 196 deletions
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 38e08ae..469b4f1 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -2242,7 +2242,9 @@ public class PowerManagerService extends IPowerManager.Stub } else { newValue = endValue; mHighestLightSensorValue = endSensorValue; - mInitialAnimation = false; + if (endValue > 0) { + mInitialAnimation = false; + } } if (mDebugLightAnimation) { @@ -2290,7 +2292,7 @@ public class PowerManagerService extends IPowerManager.Stub currentMask = mask; duration = (int) (mWindowScaleAnimation * animationDuration); startTimeMillis = SystemClock.elapsedRealtime(); - mInitialAnimation = currentValue == 0 && target > 0; + mInitialAnimation = mInitialAnimation && target > 0; if (mDebugLightAnimation) { Slog.v(TAG, "animateTo(target=" + target @@ -2608,7 +2610,8 @@ public class PowerManagerService extends IPowerManager.Stub } }; - private boolean mInitialAnimation; // used to prevent lightsensor changes while turning on + /** used to prevent lightsensor changes while turning on. */ + private boolean mInitialAnimation = true; private void dockStateChanged(int state) { synchronized (mLocks) { diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index c7b336f..c74dd00 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -198,7 +198,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } // TODO: Respect allowImplicitlySelectedSubtype - // TODO: Save SpellCheckerSubtype by supported languages. + // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale". @Override public SpellCheckerSubtype getCurrentSpellCheckerSubtype( String locale, boolean allowImplicitlySelectedSubtype) { @@ -250,10 +250,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { for (int i = 0; i < sci.getSubtypeCount(); ++i) { final SpellCheckerSubtype scs = sci.getSubtypeAt(i); if (hashCode == 0) { - if (candidateLocale.equals(locale)) { + final String scsLocale = scs.getLocale(); + if (candidateLocale.equals(scsLocale)) { return scs; } else if (candidate == null) { - final String scsLocale = scs.getLocale(); if (candidateLocale.length() >= 2 && scsLocale.length() >= 2 && candidateLocale.startsWith(scsLocale)) { // Fall back to the applicable language diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index c936ef9..d1f92a7 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -65,7 +65,7 @@ class UiModeManagerService extends IUiModeManager.Stub { // Enable launching of applications when entering the dock. private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true; - private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = false; + private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true; private static final int MSG_UPDATE_TWILIGHT = 0; private static final int MSG_ENABLE_LOCATION_UPDATES = 1; @@ -120,7 +120,7 @@ class UiModeManagerService extends IUiModeManager.Stub { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); return intent; } - + // The broadcast receiver which receives the result of the ordered broadcast sent when // the dock state changes. The original ordered broadcast is sent with an initial result // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., @@ -130,7 +130,7 @@ class UiModeManagerService extends IUiModeManager.Stub { public void onReceive(Context context, Intent intent) { if (getResultCode() != Activity.RESULT_OK) { if (LOG) { - Slog.v(TAG, "Handling broadcast result for action " + intent.getAction() + Slog.v(TAG, "Handling broadcast result for action " + intent.getAction() + ": canceled: " + getResultCode()); } return; @@ -138,7 +138,7 @@ class UiModeManagerService extends IUiModeManager.Stub { final int enableFlags = intent.getIntExtra("enableFlags", 0); final int disableFlags = intent.getIntExtra("disableFlags", 0); - + synchronized (mLock) { // Launch a dock activity String category = null; @@ -166,15 +166,15 @@ class UiModeManagerService extends IUiModeManager.Stub { if (LOG) { Slog.v(TAG, String.format( - "Handling broadcast result for action %s: enable=0x%08x disable=0x%08x category=%s", + "Handling broadcast result for action %s: enable=0x%08x disable=0x%08x category=%s", intent.getAction(), enableFlags, disableFlags, category)); } - + if (category != null) { // This is the new activity that will serve as home while // we are in care mode. Intent homeIntent = buildHomeIntent(category); - + // Now we are going to be careful about switching the // configuration and starting the activity -- we need to // do this in a specific order under control of the @@ -479,8 +479,8 @@ class UiModeManagerService extends IUiModeManager.Stub { } if (LOG) { - Slog.d(TAG, - "updateConfigurationLocked: mDockState=" + mDockState + Slog.d(TAG, + "updateConfigurationLocked: mDockState=" + mDockState + "; mCarMode=" + mCarModeEnabled + "; mNightMode=" + mNightMode + "; uiMode=" + uiMode); @@ -657,7 +657,7 @@ class UiModeManagerService extends IUiModeManager.Stub { boolean mNetworkListenerEnabled; boolean mDidFirstInit; long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS; - + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -682,12 +682,12 @@ class UiModeManagerService extends IUiModeManager.Stub { // since we last requested an update. return; } - + // Unregister the current location monitor, so we can // register a new one for it to get an immediate update. mNetworkListenerEnabled = false; mLocationManager.removeUpdates(mEmptyLocationListener); - + // Fall through to re-register listener. case MSG_ENABLE_LOCATION_UPDATES: // enable network provider to receive at least location updates for a given diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java index 53d1f0e..96ac493 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -139,11 +139,14 @@ class WiredAccessoryObserver extends UEventObserver { private final Context mContext; private final WakeLock mWakeLock; // held while there is a pending route change + private final AudioManager mAudioManager; + public WiredAccessoryObserver(Context context) { mContext = context; PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver"); mWakeLock.setReferenceCounted(false); + mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); context.registerReceiver(new BootCompletedReceiver(), new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); @@ -250,106 +253,65 @@ class WiredAccessoryObserver extends UEventObserver { mPrevHeadsetState = mHeadsetState; mHeadsetState = headsetState; - if (headsetState == 0) { - if (mContext.getResources().getBoolean( - com.android.internal.R.bool.config_sendAudioBecomingNoisy)) { - Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); - mContext.sendBroadcast(intent); - } - - // It can take hundreds of ms flush the audio pipeline after - // apps pause audio playback, but audio route changes are - // immediate, so delay the route change by 1000ms. - // This could be improved once the audio sub-system provides an - // interface to clear the audio pipeline. - delay = 1000; - } else { - // Insert the same delay for headset connection so that the connection event is not - // broadcast before the disconnection event in case of fast removal/insertion - if (mHandler.hasMessages(0)) { - delay = 1000; - } - } mWakeLock.acquire(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(0, - mHeadsetState, - mPrevHeadsetState, - mHeadsetName), - delay); + mHandler.sendMessage(mHandler.obtainMessage(0, + mHeadsetState, + mPrevHeadsetState, + mHeadsetName)); } - private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) { + private synchronized final void setDevicesState(int headsetState, + int prevHeadsetState, + String headsetName) { int allHeadsets = SUPPORTED_HEADSETS; for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { if ((curHeadset & allHeadsets) != 0) { - sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName); + setDeviceState(curHeadset, headsetState, prevHeadsetState, headsetName); allHeadsets &= ~curHeadset; } } } - private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) { + private final void setDeviceState(int headset, + int headsetState, + int prevHeadsetState, + String headsetName) { if ((headsetState & headset) != (prevHeadsetState & headset)) { + int device; + int state; - int state = 0; if ((headsetState & headset) != 0) { state = 1; + } else { + state = 0; } - if((headset == BIT_USB_HEADSET_ANLG) || (headset == BIT_USB_HEADSET_DGTL) || - (headset == BIT_HDMI_AUDIO)) { - Intent intent; - - // Pack up the values and broadcast them to everyone - if (headset == BIT_USB_HEADSET_ANLG) { - intent = new Intent(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - intent.putExtra("state", state); - intent.putExtra("name", headsetName); - ActivityManagerNative.broadcastStickyIntent(intent, null); - } else if (headset == BIT_USB_HEADSET_DGTL) { - intent = new Intent(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - intent.putExtra("state", state); - intent.putExtra("name", headsetName); - ActivityManagerNative.broadcastStickyIntent(intent, null); - } else if (headset == BIT_HDMI_AUDIO) { - intent = new Intent(Intent.ACTION_HDMI_AUDIO_PLUG); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - intent.putExtra("state", state); - intent.putExtra("name", headsetName); - ActivityManagerNative.broadcastStickyIntent(intent, null); - } - if (LOG) Slog.v(TAG, "Intent.ACTION_USB_HEADSET_PLUG: state: "+state+" name: "+headsetName); - // TODO: Should we require a permission? + if (headset == BIT_HEADSET) { + device = AudioManager.DEVICE_OUT_WIRED_HEADSET; + } else if (headset == BIT_HEADSET_NO_MIC){ + device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; + } else if (headset == BIT_USB_HEADSET_ANLG) { + device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; + } else if (headset == BIT_USB_HEADSET_DGTL) { + device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; + } else if (headset == BIT_HDMI_AUDIO) { + device = AudioManager.DEVICE_OUT_AUX_DIGITAL; + } else { + Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); + return; } - if((headset == BIT_HEADSET) || (headset == BIT_HEADSET_NO_MIC)) { - // Pack up the values and broadcast them to everyone - Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - //int state = 0; - int microphone = 0; + if (LOG) + Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected")); - if ((headset & HEADSETS_WITH_MIC) != 0) { - microphone = 1; - } - - intent.putExtra("state", state); - intent.putExtra("name", headsetName); - intent.putExtra("microphone", microphone); - - if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone); - // TODO: Should we require a permission? - ActivityManagerNative.broadcastStickyIntent(intent, null); - } + mAudioManager.setWiredDeviceConnectionState(device, state, headsetName); } } private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { - sendIntents(msg.arg1, msg.arg2, (String)msg.obj); + setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); } }; diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 039efbd..3e8f512 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -104,10 +104,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE = "registerUiTestAutomationService"; + private static final char COMPONENT_NAME_SEPARATOR = ':'; + private static final int OWN_PROCESS_ID = android.os.Process.myPid(); private static final int MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG = 1; + private static final int MSG_TOGGLE_TOUCH_EXPLORATION = 2; + private static int sIdCounter = 0; private static int sNextWindowId; @@ -127,12 +131,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); + private final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<ComponentName>(); + private final SparseArray<AccessibilityConnectionWrapper> mWindowIdToInteractionConnectionWrapperMap = new SparseArray<AccessibilityConnectionWrapper>(); private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>(); - private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':'); + private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); private final Rect mTempRect = new Rect(); @@ -164,6 +170,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private boolean mTouchExplorationGestureStarted; + private AlertDialog mEnableTouchExplorationDialog; + /** * Creates a new instance. * @@ -208,7 +216,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { String compPkg = comp.getPackageName(); if (compPkg.equals(packageName)) { it.remove(); - updateEnabledAccessibilitySerivcesSettingLocked(mEnabledServices); + // Update the enabled services setting. + persistComponentNamesToSettingLocked( + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + mEnabledServices); + // Update the touch exploration granted services setting. + mTouchExplorationGrantedServices.remove(comp); + persistComponentNamesToSettingLocked( + Settings.Secure. + TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, + mEnabledServices); return; } } @@ -219,7 +236,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { synchronized (mLock) { - boolean changed = false; Iterator<ComponentName> it = mEnabledServices.iterator(); while (it.hasNext()) { ComponentName comp = it.next(); @@ -230,13 +246,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return true; } it.remove(); - changed = true; + persistComponentNamesToSettingLocked( + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + mEnabledServices); } } } - if (changed) { - updateEnabledAccessibilitySerivcesSettingLocked(mEnabledServices); - } return false; } } @@ -248,33 +263,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // We will update when the automation service dies. if (mUiAutomationService == null) { populateAccessibilityServiceListLocked(); + populateEnabledAccessibilityServicesLocked(); + populateTouchExplorationGrantedAccessibilityServicesLocked(); handleAccessibilityEnabledSettingChangedLocked(); handleTouchExplorationEnabledSettingChangedLocked(); updateInputFilterLocked(); sendStateToClientsLocked(); } } - return; } super.onReceive(context, intent); } - - private void updateEnabledAccessibilitySerivcesSettingLocked( - Set<ComponentName> enabledServices) { - Iterator<ComponentName> it = enabledServices.iterator(); - StringBuilder str = new StringBuilder(); - while (it.hasNext()) { - if (str.length() > 0) { - str.append(':'); - } - str.append(it.next().flattenToShortString()); - } - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - str.toString()); - } }; // package changes @@ -338,6 +339,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { // We will update when the automation service dies. if (mUiAutomationService == null) { + populateEnabledAccessibilityServicesLocked(); + manageServicesLocked(); + } + } + } + }); + + Uri touchExplorationGrantedServicesUri = Settings.Secure.getUriFor( + Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); + contentResolver.registerContentObserver(touchExplorationGrantedServicesUri, false, + new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + synchronized (mLock) { + // We will update when the automation service dies. + if (mUiAutomationService == null) { + populateTouchExplorationGrantedAccessibilityServicesLocked(); + unbindAllServicesLocked(); manageServicesLocked(); } } @@ -647,6 +667,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + private void populateEnabledAccessibilityServicesLocked() { + populateComponentNamesFromSettingLocked( + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + mEnabledServices); + } + + private void populateTouchExplorationGrantedAccessibilityServicesLocked() { + populateComponentNamesFromSettingLocked( + Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, + mTouchExplorationGrantedServices); + } + /** * Performs {@link AccessibilityService}s delayed notification. The delay is configurable * and denotes the period after the last event before notifying the service. @@ -689,7 +721,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mServices.add(service); mComponentNameToServiceMap.put(service.mComponentName, service); updateInputFilterLocked(); - tryEnableTouchExploration(service); + tryEnableTouchExplorationLocked(service); } catch (RemoteException e) { /* do nothing */ } @@ -710,7 +742,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { service.unlinkToOwnDeath(); service.dispose(); updateInputFilterLocked(); - tryDisableTouchExploration(service); + tryDisableTouchExplorationLocked(service); return removed; } @@ -762,7 +794,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * Manages services by starting enabled ones and stopping disabled ones. */ private void manageServicesLocked() { - populateEnabledServicesLocked(mEnabledServices); final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices, mEnabledServices); // No enabled installed services => disable accessibility to avoid @@ -789,20 +820,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } /** - * Populates a list with the {@link ComponentName}s of all enabled - * {@link AccessibilityService}s. + * Populates a set with the {@link ComponentName}s stored in a colon + * separated value setting. * - * @param enabledServices The list. + * @param settingName The setting to parse. + * @param outComponentNames The output component names. */ - private void populateEnabledServicesLocked(Set<ComponentName> enabledServices) { - enabledServices.clear(); + private void populateComponentNamesFromSettingLocked(String settingName, + Set<ComponentName> outComponentNames) { + outComponentNames.clear(); - String servicesValue = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); + String settingValue = Settings.Secure.getString(mContext.getContentResolver(), settingName); - if (servicesValue != null) { + if (settingValue != null) { TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(servicesValue); + splitter.setString(settingValue); while (splitter.hasNext()) { String str = splitter.next(); if (str == null || str.length() <= 0) { @@ -810,13 +842,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } ComponentName enabledService = ComponentName.unflattenFromString(str); if (enabledService != null) { - enabledServices.add(enabledService); + outComponentNames.add(enabledService); } } } } /** + * Persists the component names in the specified setting in a + * colon separated fashion. + * + * @param settingName The setting name. + * @param componentNames The component names. + */ + private void persistComponentNamesToSettingLocked(String settingName, + Set<ComponentName> componentNames) { + StringBuilder builder = new StringBuilder(); + for (ComponentName componentName : componentNames) { + if (builder.length() > 0) { + builder.append(COMPONENT_NAME_SEPARATOR); + } + builder.append(componentName.flattenToShortString()); + } + Settings.Secure.putString(mContext.getContentResolver(), settingName, builder.toString()); + } + + /** * Updates the state of each service by starting (or keeping running) enabled ones and * stopping the rest. * @@ -935,20 +986,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; } - private void tryEnableTouchExploration(final Service service) { + private void tryEnableTouchExplorationLocked(final Service service) { if (!mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) { - if (!service.mIsAutomation) { + final boolean canToggleTouchExploration = mTouchExplorationGrantedServices.contains( + service.mComponentName); + if (!service.mIsAutomation && !canToggleTouchExploration) { mMainHandler.obtainMessage(MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG, service).sendToTarget(); } else { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1); + mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 1, 0).sendToTarget(); } } } - private void tryDisableTouchExploration(Service service) { - if (mIsTouchExplorationEnabled && service.mReqeustTouchExplorationMode) { + private void tryDisableTouchExplorationLocked(Service service) { + if (mIsTouchExplorationEnabled) { synchronized (mLock) { final int serviceCount = mServices.size(); for (int i = 0; i < serviceCount; i++) { @@ -957,8 +1009,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return; } } - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0); + mMainHandler.obtainMessage(MSG_TOGGLE_TOUCH_EXPLORATION, 0, 0).sendToTarget(); } } } @@ -995,32 +1046,54 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void handleMessage(Message msg) { final int type = msg.what; switch (type) { + case MSG_TOGGLE_TOUCH_EXPLORATION: { + final int value = msg.arg1; + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, value); + } break; case MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG: { - Service service = (Service) msg.obj; + final Service service = (Service) msg.obj; String label = service.mResolveInfo.loadLabel( mContext.getPackageManager()).toString(); - final AlertDialog dialog = new AlertDialog.Builder(mContext) - .setIcon(android.R.drawable.ic_dialog_alert) - .setPositiveButton(android.R.string.ok, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1); - } - }) - .setNegativeButton(android.R.string.cancel, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) - .setTitle(R.string.enable_explore_by_touch_warning_title) - .setMessage(mContext.getString( - R.string.enable_explore_by_touch_warning_message, label)) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); - dialog.setCanceledOnTouchOutside(true); - dialog.show(); + synchronized (mLock) { + if (mIsTouchExplorationEnabled) { + return; + } + if (mEnableTouchExplorationDialog != null + && mEnableTouchExplorationDialog.isShowing()) { + return; + } + mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(android.R.string.ok, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // The user allowed the service to toggle touch exploration. + mTouchExplorationGrantedServices.add(service.mComponentName); + persistComponentNamesToSettingLocked( + Settings.Secure. + TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, + mTouchExplorationGrantedServices); + // Enable touch exploration. + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1); + } + }) + .setNegativeButton(android.R.string.cancel, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .setTitle(R.string.enable_explore_by_touch_warning_title) + .setMessage(mContext.getString( + R.string.enable_explore_by_touch_warning_message, label)) + .create(); + mEnableTouchExplorationDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); + mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); + mEnableTouchExplorationDialog.show(); + } } } } @@ -1143,8 +1216,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mRequestTouchExplorationMode = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; + // If this service is up and running we may have to enable touch + // exploration, otherwise this will happen when the service connects. synchronized (mLock) { - tryAddServiceLocked(this); + if (isConfigured()) { + if (mRequestTouchExplorationMode) { + tryEnableTouchExplorationLocked(this); + } else { + tryDisableTouchExplorationLocked(this); + } + } } } @@ -1496,6 +1577,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (mIsAutomation) { mUiAutomationService = null; + populateEnabledAccessibilityServicesLocked(); + populateTouchExplorationGrantedAccessibilityServicesLocked(); + handleAccessibilityEnabledSettingChangedLocked(); sendStateToClientsLocked(); diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index b0b2b8d..4c38ab9 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -1532,7 +1532,7 @@ public class TouchExplorer { */ public ReceivedPointerTracker(Context context) { mThresholdActivePointer = - ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER; + ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER;//Heie govna } /** diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 9d9b5b8..febbd32 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -176,6 +176,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false; static final boolean DEBUG_VISBILITY = localLOGV || false; static final boolean DEBUG_PROCESSES = localLOGV || false; + static final boolean DEBUG_PROCESS_OBSERVERS = localLOGV || false; static final boolean DEBUG_PROVIDER = localLOGV || false; static final boolean DEBUG_URI_PERMISSION = localLOGV || false; static final boolean DEBUG_USER_LEAVING = localLOGV || false; @@ -764,8 +765,24 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mAutoStopProfiler = false; String mOpenGlTraceApp = null; + static class ProcessChangeItem { + static final int CHANGE_ACTIVITIES = 1<<0; + static final int CHANGE_IMPORTANCE= 1<<1; + int changes; + int uid; + int pid; + int importance; + boolean foregroundActivities; + } + final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<IProcessObserver>(); + ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; + + final ArrayList<ProcessChangeItem> mPendingProcessChanges + = new ArrayList<ProcessChangeItem>(); + final ArrayList<ProcessChangeItem> mAvailProcessChanges + = new ArrayList<ProcessChangeItem>(); /** * Callback of last caller to {@link #requestPss}. @@ -855,7 +872,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int CLEAR_DNS_CACHE = 28; static final int UPDATE_HTTP_PROXY = 29; static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30; - static final int DISPATCH_FOREGROUND_ACTIVITIES_CHANGED = 31; + static final int DISPATCH_PROCESSES_CHANGED = 31; static final int DISPATCH_PROCESS_DIED = 32; static final int REPORT_MEM_USAGE = 33; @@ -1195,11 +1212,8 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } - case DISPATCH_FOREGROUND_ACTIVITIES_CHANGED: { - final int pid = msg.arg1; - final int uid = msg.arg2; - final boolean foregroundActivities = (Boolean) msg.obj; - dispatchForegroundActivitiesChanged(pid, uid, foregroundActivities); + case DISPATCH_PROCESSES_CHANGED: { + dispatchProcessesChanged(); break; } case DISPATCH_PROCESS_DIED: { @@ -2260,19 +2274,43 @@ public final class ActivityManagerService extends ActivityManagerNative void reportResumedActivityLocked(ActivityRecord r) { //Slog.i(TAG, "**** REPORT RESUME: " + r); - - final int identHash = System.identityHashCode(r); updateUsageStats(r, true); } - private void dispatchForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { + private void dispatchProcessesChanged() { + int N; + synchronized (this) { + N = mPendingProcessChanges.size(); + if (mActiveProcessChanges.length < N) { + mActiveProcessChanges = new ProcessChangeItem[N]; + } + mPendingProcessChanges.toArray(mActiveProcessChanges); + mAvailProcessChanges.addAll(mPendingProcessChanges); + mPendingProcessChanges.clear(); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "*** Delivering " + N + " process changes"); + } int i = mProcessObservers.beginBroadcast(); while (i > 0) { i--; final IProcessObserver observer = mProcessObservers.getBroadcastItem(i); if (observer != null) { try { - observer.onForegroundActivitiesChanged(pid, uid, foregroundActivities); + for (int j=0; j<N; j++) { + ProcessChangeItem item = mActiveProcessChanges[j]; + if ((item.changes&ProcessChangeItem.CHANGE_ACTIVITIES) != 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "ACTIVITIES CHANGED pid=" + + item.pid + " uid=" + item.uid + ": " + + item.foregroundActivities); + observer.onForegroundActivitiesChanged(item.pid, item.uid, + item.foregroundActivities); + } + if ((item.changes&ProcessChangeItem.CHANGE_IMPORTANCE) != 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "IMPORTANCE CHANGED pid=" + + item.pid + " uid=" + item.uid + ": " + item.importance); + observer.onImportanceChanged(item.pid, item.uid, + item.importance); + } + } } catch (RemoteException e) { } } @@ -3529,7 +3567,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=mMainStack.mHistory.size()-1; i>=0; i--) { ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); - if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) { + if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0 + && (r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS) == 0) { r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "close-sys"); } @@ -10801,6 +10840,13 @@ public final class ActivityManagerService extends ActivityManagerNative } } + for (int i = mPendingProcessChanges.size()-1; i>=0; i--) { + ProcessChangeItem item = mPendingProcessChanges.get(i); + if (item.pid == app.pid) { + mPendingProcessChanges.remove(i); + mAvailProcessChanges.add(item); + } + } mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget(); // If the caller is restarting this app, then leave it in its @@ -13733,9 +13779,6 @@ public final class ActivityManagerService extends ActivityManagerNative return (app.curAdj=app.maxAdj); } - final boolean hadForegroundActivities = app.foregroundActivities; - - app.foregroundActivities = false; app.keeping = false; app.systemNoUi = false; @@ -13743,18 +13786,22 @@ public final class ActivityManagerService extends ActivityManagerNative // important to least, and assign an appropriate OOM adjustment. int adj; int schedGroup; + boolean foregroundActivities = false; + boolean interesting = false; BroadcastQueue queue; if (app == TOP_APP) { // The last app on the list is the foreground app. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "top-activity"; - app.foregroundActivities = true; + foregroundActivities = true; + interesting = true; } else if (app.instrumentationClass != null) { // Don't want to kill running instrumentation. adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "instrumentation"; + interesting = true; } else if ((queue = isReceivingBroadcast(app)) != null) { // An app that is currently receiving a broadcast also // counts as being in the foreground for OOM killer purposes. @@ -13790,7 +13837,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean hasStoppingActivities = false; // Examine all activities if not already foreground. - if (!app.foregroundActivities && activitiesSize > 0) { + if (!foregroundActivities && activitiesSize > 0) { for (int j = 0; j < activitiesSize; j++) { final ActivityRecord r = app.activities.get(j); if (r.visible) { @@ -13801,7 +13848,7 @@ public final class ActivityManagerService extends ActivityManagerNative } schedGroup = Process.THREAD_GROUP_DEFAULT; app.hidden = false; - app.foregroundActivities = true; + foregroundActivities = true; break; } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { @@ -13809,13 +13856,13 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "pausing"; } app.hidden = false; - app.foregroundActivities = true; + foregroundActivities = true; } else if (r.state == ActivityState.STOPPING) { // We will apply the actual adjustment later, because // we want to allow this process to immediately go through // any memory trimming that is in effect. app.hidden = false; - app.foregroundActivities = true; + foregroundActivities = true; hasStoppingActivities = true; } } @@ -13838,6 +13885,10 @@ public final class ActivityManagerService extends ActivityManagerNative } } + if (app.foregroundServices) { + interesting = true; + } + if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) { // We don't want to kill the current heavy-weight process. adj = ProcessList.HEAVY_WEIGHT_APP_ADJ; @@ -14187,12 +14238,84 @@ public final class ActivityManagerService extends ActivityManagerNative } } - app.curAdj = adj; - app.curSchedGroup = schedGroup; + int importance = app.memImportance; + if (importance == 0 || adj != app.curAdj || schedGroup != app.curSchedGroup) { + app.curAdj = adj; + app.curSchedGroup = schedGroup; + if (!interesting) { + // For this reporting, if there is not something explicitly + // interesting in this process then we will push it to the + // background importance. + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; + } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; + } else if (adj >= ProcessList.SERVICE_B_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; + } else if (adj >= ProcessList.HOME_APP_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; + } else if (adj >= ProcessList.SERVICE_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; + } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE; + } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; + } else if (adj >= ProcessList.VISIBLE_APP_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; + } else if (adj >= ProcessList.FOREGROUND_APP_ADJ) { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + } else { + importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERSISTENT; + } + } - if (hadForegroundActivities != app.foregroundActivities) { - mHandler.obtainMessage(DISPATCH_FOREGROUND_ACTIVITIES_CHANGED, app.pid, app.info.uid, - app.foregroundActivities).sendToTarget(); + int changes = importance != app.memImportance ? ProcessChangeItem.CHANGE_IMPORTANCE : 0; + if (foregroundActivities != app.foregroundActivities) { + changes |= ProcessChangeItem.CHANGE_ACTIVITIES; + } + if (changes != 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes); + app.memImportance = importance; + app.foregroundActivities = foregroundActivities; + int i = mPendingProcessChanges.size()-1; + ProcessChangeItem item = null; + while (i >= 0) { + item = mPendingProcessChanges.get(i); + if (item.pid == app.pid) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item); + break; + } + i--; + } + if (i < 0) { + // No existing item in pending changes; need a new one. + final int NA = mAvailProcessChanges.size(); + if (NA > 0) { + item = mAvailProcessChanges.remove(NA-1); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item); + } else { + item = new ProcessChangeItem(); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item); + } + item.changes = 0; + item.pid = app.pid; + item.uid = app.info.uid; + if (mPendingProcessChanges.size() == 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, + "*** Enqueueing dispatch processes changed!"); + mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget(); + } + mPendingProcessChanges.add(item); + } + item.changes |= changes; + item.importance = importance; + item.foregroundActivities = foregroundActivities; + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item " + + Integer.toHexString(System.identityHashCode(item)) + + " " + app.toShortString() + ": changes=" + item.changes + + " importance=" + item.importance + + " foreground=" + item.foregroundActivities + + " type=" + app.adjType + " source=" + app.adjSource + + " target=" + app.adjTarget); } return app.curRawAdj; diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/java/com/android/server/am/ContentProviderConnection.java index 84f8f02..7f69b24 100644 --- a/services/java/com/android/server/am/ContentProviderConnection.java +++ b/services/java/com/android/server/am/ContentProviderConnection.java @@ -17,6 +17,8 @@ package com.android.server.am; import android.os.Binder; +import android.os.SystemClock; +import android.util.TimeUtils; /** * Represents a link between a content provider and client. @@ -24,6 +26,7 @@ import android.os.Binder; public class ContentProviderConnection extends Binder { public final ContentProviderRecord provider; public final ProcessRecord client; + public final long createTime; public int stableCount; public int unstableCount; // The client of this connection is currently waiting for the provider to appear. @@ -39,6 +42,7 @@ public class ContentProviderConnection extends Binder { public ContentProviderConnection(ContentProviderRecord _provider, ProcessRecord _client) { provider = _provider; client = _client; + createTime = SystemClock.elapsedRealtime(); } public String toString() { @@ -83,5 +87,8 @@ public class ContentProviderConnection extends Binder { if (dead) { sb.append(" DEAD"); } + long nowReal = SystemClock.elapsedRealtime(); + sb.append(" "); + TimeUtils.formatDuration(nowReal-createTime, sb); } } diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 8a3ba7f..cba9480 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -69,6 +69,7 @@ class ProcessRecord { int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class int trimMemoryLevel; // Last selected memory trimming level + int memImportance; // Importance constant computed from curAdj boolean serviceb; // Process currently is on the service B list boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index 4b4a89d..3a767c2 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -19,9 +19,8 @@ package com.android.server.am; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; import android.os.UserId; +import android.util.Slog; import java.io.PrintWriter; @@ -69,6 +68,8 @@ class TaskRecord extends ThumbnailHolder { _intent.setSourceBounds(null); } } + if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG, + "Setting Intent of " + this + " to " + _intent); intent = _intent; realActivity = _intent != null ? _intent.getComponent() : null; origActivity = null; @@ -80,6 +81,8 @@ class TaskRecord extends ThumbnailHolder { targetIntent.setComponent(targetComponent); targetIntent.setSelector(null); targetIntent.setSourceBounds(null); + if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG, + "Setting Intent of " + this + " to target " + targetIntent); intent = targetIntent; realActivity = targetComponent; origActivity = _intent.getComponent(); @@ -103,9 +106,10 @@ class TaskRecord extends ThumbnailHolder { } void dump(PrintWriter pw, String prefix) { - if (numActivities != 0 || rootWasReset) { + if (numActivities != 0 || rootWasReset || userId != 0) { pw.print(prefix); pw.print("numActivities="); pw.print(numActivities); - pw.print(" rootWasReset="); pw.println(rootWasReset); + pw.print(" rootWasReset="); pw.print(rootWasReset); + pw.print(" userId="); pw.println(userId); } if (affinity != null) { pw.print(prefix); pw.print("affinity="); pw.println(affinity); diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index c82f37c..c4abac9 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -396,6 +396,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override + public void onImportanceChanged(int pid, int uid, int importance) { + } + + @Override public void onProcessDied(int pid, int uid) { mHandler.obtainMessage(MSG_PROCESS_DIED, pid, uid).sendToTarget(); } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 10919f2..efbf0d4 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -5437,8 +5437,8 @@ public class WindowManagerService extends IWindowManager.Stub // window. including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); - if (maxLayer < ws.mWinAnimator.mAnimLayer) { - maxLayer = ws.mWinAnimator.mAnimLayer; + if (maxLayer < ws.mWinAnimator.mSurfaceLayer) { + maxLayer = ws.mWinAnimator.mSurfaceLayer; } // Don't include wallpaper in bounds calculation diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index d3b667f..9e5e84b 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -225,9 +225,10 @@ bool SensorService::threadLoop() { ALOGD("nuSensorService thread starting..."); - const size_t numEventMax = 16 * (1 + mVirtualSensorList.size()); - sensors_event_t buffer[numEventMax]; - sensors_event_t scratch[numEventMax]; + const size_t numEventMax = 16; + const size_t minBufferSize = numEventMax + numEventMax * mVirtualSensorList.size(); + sensors_event_t buffer[minBufferSize]; + sensors_event_t scratch[minBufferSize]; SensorDevice& device(SensorDevice::getInstance()); const size_t vcount = mVirtualSensorList.size(); @@ -255,10 +256,17 @@ bool SensorService::threadLoop() fusion.process(event[i]); } } - for (size_t i=0 ; i<size_t(count) ; i++) { + for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) { for (size_t j=0 ; j<activeVirtualSensorCount ; j++) { + if (count + k >= minBufferSize) { + ALOGE("buffer too small to hold all events: " + "count=%u, k=%u, size=%u", + count, k, minBufferSize); + break; + } sensors_event_t out; - if (virtualSensors.valueAt(j)->process(&out, event[i])) { + SensorInterface* si = virtualSensors.valueAt(j); + if (si->process(&out, event[i])) { buffer[count + k] = out; k++; } |
