1. add View::postInvalidateDelayed;2.fix progressbar's crash caused by View::postInvalidate

This commit is contained in:
houzh 2023-12-07 16:02:27 +08:00
parent 124b28111e
commit b38f04a3ec
8 changed files with 207 additions and 28 deletions

View File

@ -46,6 +46,7 @@ public:
std::streambuf::pos_type seekoff(std::streambuf::off_type off, std::ios_base::seekdir way,
std::ios_base::openmode mode/*ios_base::in | ios_base::out*/)override;
};
struct MemoryInputStream: virtual MemoryBuf, std::istream {
MemoryInputStream(char const* base, size_t size)
: MemoryBuf(base, size)

View File

@ -4973,7 +4973,32 @@ void View::invalidate(bool invalidateCache){
}
void View::postInvalidate(){
postDelayed([this](){ invalidate(true);},30);
postInvalidateDelayed(0);
}
void View::postInvalidate(int left,int top,int width,int height){
postInvalidateDelayed(0,left,top,width,height);
}
void View::postInvalidateDelayed(long delayMilliseconds) {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
if (mAttachInfo) {
mAttachInfo->mRootView->dispatchInvalidateDelayed(this, delayMilliseconds);
}
}
void View::postInvalidateDelayed(long delayMilliseconds, int left, int top,
int width, int height) {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
if (mAttachInfo) {
AttachInfo::InvalidateInfo* info = AttachInfo::InvalidateInfo::obtain();
info->target= this;
info->rect.set(left,top,width,height);
mAttachInfo->mRootView->dispatchInvalidateRectDelayed(info, delayMilliseconds);
}
}
void View::cleanupDraw(){
@ -5215,7 +5240,7 @@ bool View::requestFocusNoSearch(int direction,Rect*previouslyFocusedRect) {
bool View::requestFocusFromTouch(){
if(isInTouchMode()){
ViewGroup* viewRoot = (ViewGroup*)getRootView();
//if(viewRoot)viewRoot->ensureTouchMode(false);
if(viewRoot)viewRoot->ensureTouchMode(false);
}
return requestFocus(View::FOCUS_DOWN);
}
@ -7218,6 +7243,28 @@ void View::measure(int widthMeasureSpec, int heightMeasureSpec){
//mMeasureCache.insert(std::pair<Size,Size>(key,szMeasured)); // suppress sign extension
}
View::AttachInfo::InvalidateInfo::InvalidateInfo(){
target = nullptr;
rect.set(0,0,0,0);
}
std::vector<View::AttachInfo::InvalidateInfo*>View::AttachInfo::InvalidateInfo::sPool;
View::AttachInfo::InvalidateInfo*View::AttachInfo::InvalidateInfo::obtain(){
AttachInfo::InvalidateInfo*ret = nullptr;
if(sPool.empty()){
ret = new AttachInfo::InvalidateInfo();
}else{
ret = sPool.back();
sPool.pop_back();
}
ret->rect.set(0,0,0,0);
return ret;
}
void View::AttachInfo::InvalidateInfo::recycle(){
sPool.push_back(this);
}
View::AttachInfo::AttachInfo(Context*ctx){
mHardwareAccelerated =false;
mWindowVisibility = VISIBLE;

View File

@ -194,8 +194,20 @@ protected:
ForegroundInfo();
~ForegroundInfo();
};
public:
class AttachInfo{
public:
class InvalidateInfo{
private:
static std::vector<InvalidateInfo*>sPool;
public:
View* target;
Rect rect;
static InvalidateInfo*obtain();
InvalidateInfo();
void recycle();
};
ViewGroup*mRootView;
bool mHardwareAccelerated;
float mApplicationScale;
@ -687,6 +699,9 @@ public:
bool isDirty()const;
void postInvalidate();
void postInvalidate(int left, int top, int width, int height);
void postInvalidateDelayed(long delayMilliseconds);
void postInvalidateDelayed(long delayMilliseconds, int left, int top,int width, int height);
void postInvalidateOnAnimation();
void postInvalidateOnAnimation(int left, int top, int width, int height);
void invalidateDrawable(Drawable& who)override;

View File

@ -253,6 +253,10 @@ int ViewGroup::getTextAlignment()const{
return View::TEXT_ALIGNMENT_RESOLVED_DEFAULT;
}
bool ViewGroup::ensureTouchMode(bool){
return false;
}
void ViewGroup::cancelAndClearTouchTargets(MotionEvent* event){
if (mFirstTouchTarget==nullptr)return;
@ -890,7 +894,13 @@ void ViewGroup::finishAnimatingView(View* view, Animation* animation) {
void ViewGroup::dispatchInvalidateOnAnimation(View* view){
}
void ViewGroup::dispatchInvalidateRectOnAnimation(View*,const Rect&){
void ViewGroup::dispatchInvalidateRectOnAnimation(View*view,const Rect&rect){
}
void ViewGroup::dispatchInvalidateDelayed(View* view,long){
}
void ViewGroup::dispatchInvalidateRectDelayed(const AttachInfo::InvalidateInfo*,long){
}
void ViewGroup::cancelInvalidate(View* view){

View File

@ -261,6 +261,7 @@ public:
ViewGroup(int x,int y,int w,int h);
ViewGroup(Context*ctx,const AttributeSet& attrs);
virtual ~ViewGroup();
virtual bool ensureTouchMode(bool);
bool getTouchscreenBlocksFocus()const;
bool shouldBlockFocusForTouchscreen()const;
int getDescendantFocusability()const;
@ -395,6 +396,8 @@ public:
virtual void dispatchInvalidateOnAnimation(View* view);
virtual void dispatchInvalidateRectOnAnimation(View*,const Rect&);
virtual void dispatchInvalidateDelayed(View*,long delay);
virtual void dispatchInvalidateRectDelayed(const AttachInfo::InvalidateInfo*,long delay);
virtual void cancelInvalidate(View* view);
virtual bool showContextMenuForChild(View* originalView);
virtual bool showContextMenuForChild(View* originalView, float x, float y);

View File

@ -108,6 +108,94 @@ void Window::bringToFront(){
WindowManager::getInstance().bringToFront(this);
}
bool Window::ensureTouchMode(bool inTouchMode) {
LOGD("ensureTouchMode( %d), current touch mode is ",inTouchMode, mAttachInfo->mInTouchMode);
if (mAttachInfo->mInTouchMode == inTouchMode) return false;
// tell the window manager
/*try {
IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService();
windowManager.setInTouchMode(inTouchMode, getDisplayId());
} catch (RemoteException e) {
throw new RuntimeException(e);
}*/
// handle the change
return ensureTouchModeLocally(inTouchMode);
}
bool Window::ensureTouchModeLocally(bool inTouchMode) {
LOGD("ensureTouchModeLocally(%d), current touch mode is ",inTouchMode, mAttachInfo->mInTouchMode);
if (mAttachInfo->mInTouchMode == inTouchMode) return false;
mAttachInfo->mInTouchMode = inTouchMode;
mAttachInfo->mTreeObserver->dispatchOnTouchModeChanged(inTouchMode);
return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
}
ViewGroup*Window::findAncestorToTakeFocusInTouchMode(View* focused) {
ViewGroup* parent = focused->getParent();
while (parent){
ViewGroup* vgParent = (ViewGroup*) parent;
if (vgParent->getDescendantFocusability() == ViewGroup::FOCUS_AFTER_DESCENDANTS
&& vgParent->isFocusableInTouchMode()) {
return vgParent;
}
/*if (vgParent->isRootNamespace()) {
return nullptr;
} else */{
parent = vgParent->getParent();
}
}
return nullptr;
}
bool Window::enterTouchMode() {
if (hasFocus()) {
// note: not relying on mFocusedView here because this could
// be when the window is first being added, and mFocused isn't
// set yet.
View* focused = findFocus();
if (focused && !focused->isFocusableInTouchMode()) {
ViewGroup* ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
if (ancestorToTakeFocus != nullptr) {
// there is an ancestor that wants focus after its
// descendants that is focusable in touch mode.. give it
// focus
return ancestorToTakeFocus->requestFocus();
} else {
// There's nothing to focus. Clear and propagate through the
// hierarchy, but don't attempt to place new focus.
//focused->clearFocusInternal(nullptr, true, false);
return true;
}
}
}
return false;
}
bool Window::leaveTouchMode() {
if (mChildren.size()) {
if (hasFocus()) {
View* focusedView = findFocus();
if (dynamic_cast<ViewGroup*>(focusedView)==nullptr) {
// some view has focus, let it keep it
return false;
} else if (((ViewGroup*) focusedView)->getDescendantFocusability() !=
ViewGroup::FOCUS_AFTER_DESCENDANTS) {
// some view group has focus, and doesn't prefer its children
// over itself for focus, so let them keep it.
return false;
}
}
// find the best view to give focus to in this brave new non-touch-mode
// world
return restoreDefaultFocus();
}
return false;
}
void Window::draw(){
if(mVisibleRgn&&mVisibleRgn->get_num_rectangles()==0){
return;
@ -416,22 +504,32 @@ void Window::dispatchInvalidateRectOnAnimation(View*view,const Rect&rect){
mInvalidateOnAnimationRunnable.addViewRect(view,rect);
}
void Window::dispatchInvalidateDelayed(View*view, long delayMilliseconds){
LOGW_IF(delayMilliseconds,"Delay is NOT IMPLEMENTED");
if(0==delayMilliseconds) dispatchInvalidateOnAnimation(view);
}
void Window::dispatchInvalidateRectDelayed(const AttachInfo::InvalidateInfo*info,long delayMilliseconds){
LOGW_IF(delayMilliseconds,"Delay is NOT IMPLEMENTED");
if(0==delayMilliseconds) dispatchInvalidateRectOnAnimation(info->target,info->rect);
}
void Window::cancelInvalidate(View* view){
mInvalidateOnAnimationRunnable.removeView(view);
}
Window::InvalidateOnAnimationRunnable::InvalidateOnAnimationRunnable(){
mOwner =nullptr;
mPosted=false;
mOwner = nullptr;
mPosted= false;
}
void Window::InvalidateOnAnimationRunnable::setOwner(Window*w){
mOwner=w;
}
std::vector<Window::InvalidateInfo>::iterator Window::InvalidateOnAnimationRunnable::find(View*v){
std::vector<View::AttachInfo::InvalidateInfo*>::iterator Window::InvalidateOnAnimationRunnable::find(View*v){
for(auto it=mInvalidateViews.begin();it!=mInvalidateViews.end();it++){
if((*it).target == v)
if((*it)->target == v)
return it;
}
return mInvalidateViews.end();
@ -440,13 +538,13 @@ std::vector<Window::InvalidateInfo>::iterator Window::InvalidateOnAnimationRunna
void Window::InvalidateOnAnimationRunnable::addView(View* view){
auto it=find(view);
if(it==mInvalidateViews.end()){
InvalidateInfo info;
info.target = view;
info.rect.set(0,0,0,0);
AttachInfo::InvalidateInfo* info = AttachInfo::InvalidateInfo::obtain();
info->target = view;
info->rect.set(0,0,0,0);
mInvalidateViews.push_back(info);
}else{
InvalidateInfo& info=(*it);
info.rect.set(0,0,0,0);
AttachInfo::InvalidateInfo* info=(*it);
info->rect.set(0,0,0,0);
}
postIfNeededLocked();
}
@ -454,14 +552,14 @@ void Window::InvalidateOnAnimationRunnable::addView(View* view){
void Window::InvalidateOnAnimationRunnable::addViewRect(View* view,const Rect&rect){
auto it=find(view);
if(it == mInvalidateViews.end()){
InvalidateInfo info;
info.target =view;
info.rect = rect;
AttachInfo::InvalidateInfo* info = AttachInfo::InvalidateInfo::obtain();
info->target =view;
info->rect = rect;
mInvalidateViews.push_back(info);
}else{
InvalidateInfo& info=(*it);
if(!info.rect.empty())
info.rect.Union(rect);
AttachInfo::InvalidateInfo* info=(*it);
if(!info->rect.empty())
info->rect.Union(rect);
}
postIfNeededLocked();
}
@ -478,11 +576,11 @@ void Window::InvalidateOnAnimationRunnable::removeView(View* view){
void Window::InvalidateOnAnimationRunnable::run(){
mPosted = false;
std::vector<InvalidateInfo>temp = mInvalidateViews;
std::vector<View::AttachInfo::InvalidateInfo*>&temp = mInvalidateViews;
mInvalidateViews.clear();
for (auto i:temp){
Rect&r = i.rect;
View*v = i.target;
Rect&r = i->rect;
View*v = i->target;
if(r.width<=0||r.height<=0) v->invalidate();
else v->invalidate(r.left,r.top,r.width,r.height);
}
@ -491,7 +589,8 @@ void Window::InvalidateOnAnimationRunnable::run(){
void Window::InvalidateOnAnimationRunnable::postIfNeededLocked() {
if (!mPosted) {
//Choreographer::getInstance().postCallback(Choreographer::CALLBACK_ANIMATION,nullptr,this);
Runnable run;run=std::bind(&InvalidateOnAnimationRunnable::run,this);
Runnable run;
run=std::bind(&InvalidateOnAnimationRunnable::run,this);
mOwner->postDelayed(run,AnimationHandler::getFrameDelay());
mPosted = true;
}

View File

@ -14,17 +14,13 @@ protected:
friend class WindowManager;
friend class GraphDevice;
friend class UIEventSource;
struct InvalidateInfo{
View* target;
Rect rect;
};
class InvalidateOnAnimationRunnable:public Runnable{
private:
bool mPosted;
Window*mOwner;
std::vector<InvalidateInfo>mInvalidateViews;
std::vector<AttachInfo::InvalidateInfo*>mInvalidateViews;
void postIfNeededLocked();
std::vector<InvalidateInfo>::iterator find(View*v);
std::vector<AttachInfo::InvalidateInfo*>::iterator find(View*v);
public:
InvalidateOnAnimationRunnable();
void setOwner(Window*w);
@ -48,6 +44,10 @@ private:
void doLayout();
bool performFocusNavigation(KeyEvent& event);
static View*inflate(Context*ctx,std::istream&stream);
static ViewGroup*findAncestorToTakeFocusInTouchMode(View* focused);
bool ensureTouchModeLocally(bool);
bool enterTouchMode();
bool leaveTouchMode();
protected:
std::vector<View*>mLayoutRequesters;
Cairo::RefPtr<Cairo::Region>mVisibleRgn;
@ -93,6 +93,7 @@ public:
virtual void setText(const std::string&);
const std::string getText()const;
virtual View& setPos(int x,int y)override;
bool ensureTouchMode(bool inTouchMode)override;
View& setAlpha(float a);
void sendToBack();
void bringToFront();
@ -108,6 +109,8 @@ public:
bool removeCallbacks(const Runnable& what)override;
void dispatchInvalidateOnAnimation(View* view)override;
void dispatchInvalidateRectOnAnimation(View*,const Rect&)override;
void dispatchInvalidateDelayed(View*, long delayMilliseconds)override;
void dispatchInvalidateRectDelayed(const AttachInfo::InvalidateInfo*,long delayMilliseconds)override;
bool dispatchTouchEvent(MotionEvent& event)override;
void cancelInvalidate(View* view)override;
ViewGroup::LayoutParams* generateLayoutParams(const AttributeSet&)const override;

View File

@ -219,6 +219,7 @@ void ProgressBar::initProgressBar(){
mHasAnimation = false;
mInDrawing = false;
mAggregatedIsVisible = false;
mShouldStartAnimationDrawable = false;
mRefreshIsPosted = false;
mDatas.insert(std::pair<int,RefreshData>(R::id::progress,RefreshData()));
mDatas.insert(std::pair<int,RefreshData>(R::id::secondaryProgress,RefreshData()));