TaskView 类的长按事件 onLongClick 方法内发送了 DragStartEvent 事件消息,该 DragStartEvent 事件消息由 RecentsView,TaskStackView和 RecentsViewTouchHandler三个类接受处理.

a. TaskStackView

public final void onBusEvent(DragStartEvent event) {
        // Ensure that the drag task is not animated
        addIgnoreTask(event.task);

if (event.task.isFreeformTask()) {
            // Animate to the front of the stack
            mStackScroller.animateScroll(mLayoutAlgorithm.mInitialScrollP, null);
        }
  
        // Enlarge the dragged view slightly   //X轴方向放大view
        float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR;
        mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
                mTmpTransform, null);
        mTmpTransform.scale = finalScale;
        mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1;
        mTmpTransform.dimAlpha = 0f;
        updateTaskViewToTransform(event.taskView, mTmpTransform,
                new AnimationProps(DRAG_SCALE_DURATION, Interpolators.FAST_OUT_SLOW_IN));
    }

b. RecentsView

public final void onBusEvent(DragStartEvent event) {

// 显示Dock可见区域
        updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
                true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
                TaskStack.DockState.NONE.viewState.hintTextAlpha,
                true /* animateAlpha */, false /* animateBounds */);

// Temporarily hide the stack action button without changing visibility
        if (mStackActionButton != null) {
            mStackActionButton.animate()
                    .alpha(0f)
                    .setDuration(HIDE_STACK_ACTION_BUTTON_DURATION)
                    .setInterpolator(Interpolators.ALPHA_OUT)
                    .start();
        }
    }

c.RecentsViewTouchHandler.java

/**
     * Handles dragging touch events
     */
    private void handleTouchEvent(MotionEvent ev) {

// Dock展示虚拟大区域,准备接纳

EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask,
                                    currentDropTarget));

}

EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView,
                            !cancelled ? mLastDropTarget : null));  //手指拖动结束事件

1. RecentsView.java

/**
 * This view is the the top level layout that contains TaskStacks (which are laid out according
 * to their SpaceNode bounds.
 */
public class RecentsView extends FrameLayout {

    private RecentsViewTouchHandler mTouchHandler;

    @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mTouchHandler.onInterceptTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent ev) {
return mTouchHandler.onTouchEvent(ev);
}

}

2. RecentsViewTouchHandler.java

/**
 * Handles touch events for a RecentsView.
 */
public class RecentsViewTouchHandler {

    /** Touch preprocessing for handling below */
public boolean onInterceptTouchEvent(MotionEvent ev) {
handleTouchEvent(ev);
return mDragRequested;
} /** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
handleTouchEvent(ev);
return mDragRequested;
} ...... /**
* Handles dragging touch events
*/
private void handleTouchEvent(MotionEvent ev) {
int action = ev.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownPos.set((int) ev.getX(), (int) ev.getY());
break;
case MotionEvent.ACTION_MOVE: {
float evX = ev.getX();
float evY = ev.getY();
float x = evX - mTaskViewOffset.x;
float y = evY - mTaskViewOffset.y; if (mDragRequested) {
if (!mIsDragging) {
mIsDragging = Math.hypot(evX - mDownPos.x, evY - mDownPos.y) > mDragSlop;
}
if (mIsDragging) {
int width = mRv.getMeasuredWidth();
int height = mRv.getMeasuredHeight(); DropTarget currentDropTarget = null; // Give priority to the current drop target to retain the touch handling
if (mLastDropTarget != null) {
if (mLastDropTarget.acceptsDrop((int) evX, (int) evY, width, height,
mRv.mSystemInsets, true /* isCurrentTarget */)) {
currentDropTarget = mLastDropTarget;
}
} // Otherwise, find the next target to handle this event
if (currentDropTarget == null) {
for (DropTarget target : mDropTargets) {
if (target.acceptsDrop((int) evX, (int) evY, width, height,
mRv.mSystemInsets, false /* isCurrentTarget */)) {
currentDropTarget = target;
break;
}
}
}
if (mLastDropTarget != currentDropTarget) {
mLastDropTarget = currentDropTarget;
EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask,
currentDropTarget));
} } mTaskView.setTranslationX(x);
mTaskView.setTranslationY(y);
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
if (mDragRequested) {
boolean cancelled = action == MotionEvent.ACTION_CANCEL;
if (cancelled) {
EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, null));
}
EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView,
!cancelled ? mLastDropTarget : null));
break;
}
}
}
}

}

3. RecentsView.java

public final void onBusEvent(final DragEndEvent event) {
// Handle the case where we drop onto a dock region
if (event.dropTarget instanceof TaskStack.DockState) {
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; // Hide the dock region
updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1,
false /* animateAlpha */, false /* animateBounds */); // We translated the view but we need to animate it back from the current layout-space
// rect to its final layout-space rect
Utilities.setViewFrameFromTranslation(event.taskView); // Dock the task and launch it
SystemServicesProxy ssp = Recents.getSystemServices();
      // 触发分屏
if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
final OnAnimationStartedListener startedListener =
new OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
// Remove the task and don't bother relaying out, as all the tasks will be
// relaid out when the stack changes on the multiwindow change event
mTaskStackView.getStack().removeTask(event.task, null,
true /* fromDockGesture */);
}
}; final Rect taskRect = getTaskRect(event.taskView);
IAppTransitionAnimationSpecsFuture future =
mTransitionHelper.getAppTransitionFuture(
new AnimationSpecComposer() {
@Override
public List<AppTransitionAnimationSpec> composeSpecs() {
return mTransitionHelper.composeDockAnimationSpec(
event.taskView, taskRect);
}
});
ssp.overridePendingAppTransitionMultiThumbFuture(future,
mTransitionHelper.wrapStartedListener(startedListener),
true /* scaleUp */); MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
event.task.getTopComponent().flattenToShortString());
} else {
EventBus.getDefault().send(new DragEndCancelledEvent(mStack, event.task,
event.taskView));
}
} else {
// Animate the overlay alpha back to 0
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1,
true /* animateAlpha */, false /* animateBounds */);
} // Show the stack action button again without changing visibility
if (mStackActionButton != null) {
mStackActionButton.animate()
.alpha(1f)
.setDuration(SHOW_STACK_ACTION_BUTTON_DURATION)
.setInterpolator(Interpolators.ALPHA_IN)
.start();
}
}

4.SystemServicesProxy.java

触发分屏

    /** Docks a task to the side of the screen and starts it. */
public boolean startTaskInDockedMode(int taskId, int createMode) {
if (mIam == null) return false; try {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setDockCreateMode(createMode);
options.setLaunchStackId(DOCKED_STACK_ID);
mIam.startActivityFromRecents(taskId, options.toBundle());
return true;
} catch (Exception e) {
Log.e(TAG, "Failed to dock task: " + taskId + " with createMode: " + createMode, e);
}
return false;
}

5.ActivityManagerService.java

    @Override
public final int startActivityFromRecents(int taskId, Bundle bOptions) {
// 权限检查
if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: startActivityFromRecents called without " +
START_TASKS_FROM_RECENTS;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
final long origId = Binder.clearCallingIdentity(); // 清除id,更换调用身份,升级权限
try {
synchronized (this) {
return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}

mStackSupervisor 是 ActivityStackSupervisor对象

6.ActivityStackSupervisor.java

final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
final TaskRecord task;
final int callingUid;
final String callingPackage;
final Intent intent;
final int userId;
final ActivityOptions activityOptions = (bOptions != null)
? new ActivityOptions(bOptions) : null;
final int launchStackId = (activityOptions != null)
? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
if (launchStackId == HOME_STACK_ID) {
throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+ taskId + " can't be launch in the home stack.");
} if (launchStackId == DOCKED_STACK_ID) {
mWindowManager.setDockedStackCreateState(
activityOptions.getDockCreateMode(), null /* initialBounds */); // Defer updating the stack in which recents is until the app transition is done, to
// not run into issues where we still need to draw the task in recents but the
// docked stack is already created.
deferUpdateBounds(HOME_STACK_ID);
mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
} task = anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
if (task == null) {
continueUpdateBounds(HOME_STACK_ID);
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecentsInner: Task " + taskId + " not found.");
} // Since we don't have an actual source record here, we assume that the currently focused
// activity was the source.
final ActivityStack focusedStack = getFocusedStack();
final ActivityRecord sourceRecord =
focusedStack != null ? focusedStack.topActivity() : null; if (launchStackId != INVALID_STACK_ID) {
if (task.stack.mStackId != launchStackId) {
moveTaskToStackLocked(
taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
ANIMATE);
}
}

// If the user must confirm credentials (e.g. when first launching a work app and the
// Work Challenge is present) let startActivityInPackage handle the intercepting.
if (!mService.mUserController.shouldConfirmCredentials(task.userId)
&& task.getRootActivity() != null) {
mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */);
mActivityMetricsLogger.notifyActivityLaunching();
mService.moveTaskToFrontLocked(task.taskId, 0, bOptions);
mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT,
task.getTopActivity()); // If we are launching the task in the docked stack, put it into resizing mode so
// the window renders full-screen with the background filling the void. Also only
// call this at the end to make sure that tasks exists on the window manager side.
if (launchStackId == DOCKED_STACK_ID) {
setResizingDuringAnimation(taskId);
} mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
ActivityManager.START_TASK_TO_FRONT,
sourceRecord != null ? sourceRecord.task.stack.mStackId : INVALID_STACK_ID,
sourceRecord, task.stack);
return ActivityManager.START_TASK_TO_FRONT;
}
callingUid = task.mCallingUid;
callingPackage = task.mCallingPackage;
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.userId;
int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
null, null, 0, 0, bOptions, userId, null, task);
if (launchStackId == DOCKED_STACK_ID) {
setResizingDuringAnimation(task.taskId);
}
return result;
}

mService.mUserController.shouldConfirmCredentials(task.userId)

延伸:

1. UserController.java  // 拦截应用启动?

    /**
* Returns whether the given user requires credential entry at this time. This is used to
* intercept activity launches for work apps when the Work Challenge is present.
*/
boolean shouldConfirmCredentials(int userId) {
synchronized (mService) {
if (mStartedUsers.get(userId) == null) {
return false;
}
}
if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
return false;
}
final KeyguardManager km = (KeyguardManager) mService.mContext
.getSystemService(KEYGUARD_SERVICE);
return km.isDeviceLocked(userId) && km.isDeviceSecure(userId);
}

延伸:

2.ActivityStarter.java  //应用锁实现?

private ActivityStartInterceptor mInterceptor;

final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS; ...... mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid,
options);
intent = mInterceptor.mIntent;
rInfo = mInterceptor.mRInfo;
aInfo = mInterceptor.mAInfo;
resolvedType = mInterceptor.mResolvedType;
inTask = mInterceptor.mInTask;
callingPid = mInterceptor.mCallingPid;
callingUid = mInterceptor.mCallingUid;
options = mInterceptor.mActivityOptions;
if (abort) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
RESULT_CANCELED, null);
}
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
ActivityOptions.abort(options);
return START_SUCCESS;
} ......return err;
}

延伸:

3.ActivityStartInterceptor.java

/**
* A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
* It's initialized
*/
class ActivityStartInterceptor { private final ActivityManagerService mService;
private UserManager mUserManager;
private final ActivityStackSupervisor mSupervisor; /*
* Per-intent states loaded from ActivityStarter than shouldn't be changed by any
* interception routines.
*/
private int mRealCallingPid;
private int mRealCallingUid;
private int mUserId;
private int mStartFlags;
private String mCallingPackage; /*
* Per-intent states that were load from ActivityStarter and are subject to modifications
* by the interception routines. After calling {@link #intercept} the caller should assign
* these values back to {@link ActivityStarter#startActivityLocked}'s local variables.
*/
Intent mIntent;
int mCallingPid;
int mCallingUid;
ResolveInfo mRInfo;
ActivityInfo mAInfo;
String mResolvedType;
TaskRecord mInTask;
ActivityOptions mActivityOptions; ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
mService = service;
mSupervisor = supervisor;
} void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
String callingPackage) {
mRealCallingPid = realCallingPid;
mRealCallingUid = realCallingUid;
mUserId = userId;
mStartFlags = startFlags;
mCallingPackage = callingPackage;
} void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
mUserManager = UserManager.get(mService.mContext);
mIntent = intent;
mCallingPid = callingPid;
mCallingUid = callingUid;
mRInfo = rInfo;
mAInfo = aInfo;
mResolvedType = resolvedType;
mInTask = inTask;
mActivityOptions = activityOptions;
if (interceptSuspendPackageIfNeed()) {
// Skip the rest of interceptions as the package is suspended by device admin so
// no user action can undo this.
return;
}
if (interceptQuietProfileIfNeeded()) {
// If work profile is turned off, skip the work challenge since the profile can only
// be unlocked when profile's user is running.
return;
}
interceptWorkProfileChallengeIfNeeded();
} private boolean interceptQuietProfileIfNeeded() {
// Do not intercept if the user has not turned off the profile
if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
return false;
}
IIntentSender target = mService.getIntentSenderLocked(
INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingUid, mUserId, null, null, 0,
new Intent[] {mIntent}, new String[] {mResolvedType},
FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT, null); mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId,
new IntentSender(target));
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null; final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
} private boolean interceptSuspendPackageIfNeed() {
// Do not intercept if the admin did not suspend the package
if (mAInfo == null || mAInfo.applicationInfo == null ||
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
return false;
}
DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
DevicePolicyManagerInternal.class);
if (devicePolicyManager == null) {
return false;
}
mIntent = devicePolicyManager.createPackageSuspendedDialogIntent(
mAInfo.packageName, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null; final UserInfo parent = mUserManager.getProfileParent(mUserId);
if (parent != null) {
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
} else {
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
}
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
} private boolean interceptWorkProfileChallengeIfNeeded() {
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
mResolvedType, mAInfo, mCallingPackage, mUserId);
if (interceptingIntent == null) {
return false;
}
mIntent = interceptingIntent;
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
// If we are intercepting and there was a task, convert it into an extra for the
// ConfirmCredentials intent and unassign it, as otherwise the task will move to
// front even if ConfirmCredentials is cancelled.
if (mInTask != null) {
mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
mInTask = null;
}
if (mActivityOptions == null) {
mActivityOptions = ActivityOptions.makeBasic();
} ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
if (homeActivityRecord != null && homeActivityRecord.task != null) {
// Showing credential confirmation activity in home task to avoid stopping multi-windowed
// mode after showing the full-screen credential confirmation activity.
mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId);
} final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
} /**
* Creates an intent to intercept the current activity start with Confirm Credentials if needed.
*
* @return The intercepting intent if needed.
*/
private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
ActivityInfo aInfo, String callingPackage, int userId) {
if (!mService.mUserController.shouldConfirmCredentials(userId)) {
return null;
}
// Allow direct boot aware activity to be displayed before the user is unlocked.
if (aInfo.directBootAware && mService.mUserController.isUserRunningLocked(userId,
ActivityManager.FLAG_AND_LOCKED)) {
return null;
}
final IIntentSender target = mService.getIntentSenderLocked(
INTENT_SENDER_ACTIVITY, callingPackage,
Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
new String[]{ resolvedType },
FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
final KeyguardManager km = (KeyguardManager) mService.mContext
.getSystemService(KEYGUARD_SERVICE);
final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
if (newIntent == null) {
return null;
}
newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
FLAG_ACTIVITY_TASK_ON_HOME);
newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
return newIntent;
} }

7.Divider.java  //分屏模式的中间分割栏

/**
 * Controls the docked stack divider.
 */
public class Divider extends SystemUI {

@Override
    public void start() {
        mWindowManager = new DividerWindowManager(mContext);
        update(mContext.getResources().getConfiguration());
        putComponent(Divider.class, this);
        mDockDividerVisibilityListener = new DockDividerVisibilityListener();
        SystemServicesProxy ssp = Recents.getSystemServices();
        ssp.registerDockedStackListener(mDockDividerVisibilityListener);
        mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
    }

}

8.DockedStackDividerController.java

9.DisplayContent.java

DisplayContent(Display display, WindowManagerService service) {
        mDisplay = display;
        mDisplayId = display.getDisplayId();
        display.getDisplayInfo(mDisplayInfo);
        display.getMetrics(mDisplayMetrics);
        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
        mService = service;
        initializeDisplayBaseInfo();
        mDividerControllerLocked = new DockedStackDividerController(service, this);
        mDimLayerController = new DimLayerController(this);
    }

Android 7.1 SystemUI--任务管理--场景一:长按某个缩略图,拖动分屏的流程的更多相关文章

  1. 是时候学习Android分屏开发了

    今年Google发布了Android N,Android N新增了不少功能,最受关注的自然就是分屏了. 这一功能对国内的很多手机用户并不陌生,其实很多第三方系统早已经实现了这一功能,如EMUI,Fly ...

  2. android分屏

    上手了Android N Preview,第一个不能错过的新特性就是App分屏的支持.Android7.0原生系统就可以支持两个App横屏并排或者竖屏上下摆放了.第二个新特性就是在Android TV ...

  3. Android 8.1 SystemUI虚拟导航键加载流程解析

    需求 基于MTK 8.1平台定制导航栏部分,在左边增加音量减,右边增加音量加 思路 需求开始做之前,一定要研读SystemUI Navigation模块的代码流程!!!不要直接去网上copy别人改的需 ...

  4. Android智能手机中各种音频场景下的audio data path

    上一篇文章(Android智能手机上的音频浅析)说本篇将详细讲解Android智能手机中各种音频场景下的音频数据流向,现在我们就开始.智能手机中音频的主要场景有音频播放.音频录制.语音通信等.不同场景 ...

  5. Android N分屏模式Activity生命周期的变化

    昨天Google发布了Android N Preview, balabala....我是用模拟器去验证的, 通过长按多任务窗口(口)进入分屏模式, 这里只进行了简单的测试, 不排除通过配置哪个参数, ...

  6. Android系统的三种分屏显示模式

    Google在Android 7.0中引入了一个新特性——多窗口支持,允许用户一次在屏幕上打开两个应用.在手持设备上,两个应用可以在"分屏"模式中左右并排或上下并排显示.在电视设备 ...

  7. Android零基础入门第76节:Activity数据保存和横竖屏切换

    在前面几期学习了Activity的创建.配置.启动和停止,还学了Activity的生命周期,本期一起来学习Activity有关的更多事儿. 一.数据保存 通过上一期 LogCat 窗口打印的日志可以看 ...

  8. Android分屏显示LogCat

    Eclipse里有非常多界面组件,文件列表.编辑区.类结构等等,在这么多界面组件里,再打开一个Logcat就基本没有什么空间了.与其挤在一起还不如分开成两个窗体. 或者你有两个屏幕,想一个屏幕编辑,一 ...

  9. android仿系统Launcher界面,实现分屏,左右滑动效果(ViewSwitcher)

    ViewSwitcher代表了视图切换组件, 本身继承了FrameLayout ,可以将多个View叠在一起 ,每次只显示一个组件.当程序控制从一个View切换到另个View时,ViewSwitche ...

随机推荐

  1. cglib 动态代理基础篇

    cglib 动态代理基础篇 CGlib是什么? CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. 下面我们将通过一个具体的事例来看一下CGli ...

  2. Sencha Touch2 工作笔记

    Sencha Touch2 工作笔记 Ext.dataview.List activate( this, newActiveItem, oldActiveItem, eOpts ) Fires whe ...

  3. 数据库——IN、ANY、SOME 和 ALL 操作符的使用

    sql中all,any,some用法 简介: --All:对所有数据都满足条件,整个条件才成立,例如:5大于所有返回的id select * from #A where 5>All(select ...

  4. Windows 2008 R2组策略之二——GPO初探

    与前一篇博文发表已经相去月余了,实在是有些不好意思了.感谢51CTO的大编们将小文加了推荐,这使我更加觉得自己产出太少,难于回馈大家的厚爱. 今天将这个系列的第二篇奉献给大家,以伺视听. 在上篇小文中 ...

  5. Semi-Supervised Classification with Graph Convolutional Networks

    Kipf, Thomas N., and Max Welling. "Semi-supervised classification with graph convolutional netw ...

  6. ImageNet Classification with Deep Convolutional Neural Networks 论文解读

    这个论文应该算是把深度学习应用到图片识别(ILSVRC,ImageNet large-scale Visual Recognition Challenge)上的具有重大意义的一篇文章.因为在之前,人们 ...

  7. 手动安装OpenStack Mistral

    Prepare packages: $ sudo apt-get install python-dev python-setuptools python-pip libffi-dev libxslt1 ...

  8. 【Java面试题】59 Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

    Math类中提供了三个与取整有关的方法:ceil.floor.round,这些方法的作用与它们的英文名称的含义相对应,例如,ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11. ...

  9. c++ __int64

    C++的64位整数[原]by 赤兔 在做ACM题时,经常都会遇到一些比较大的整数.而常用的内置整数类型常常显得太小了:其中long 和 int 范围是[-2^31,2^31),即-2147483648 ...

  10. 设置div滚动条

    这个是很常见的一个任务了,基本是通过CSS去实现滚动条. 滚动条 设置是否显示滚动条主要是在CSS中设置下列的属性: 代码如下: overflow:visible|auto|hidden|scroll ...