I'm really just wondering about how such a functionality can be implemented, for pure curiosity about software design.
In particular, if the OS offers a way to show an image and a way to take a screenshot, how can a messaging app (such as WhatsApp) know that a screenshot is being taken while an image is being show, and deny the screenshot accordingly?
Below are my lucubrations about the matter and my attempt to imagine how such an interaction could happen (I used a C++-like syntax just because I know C++ better than other languages).
I would assume that the OS provides a function like this to show an image
namespace os {
void showImage(Image* i, bool allowScreenshot = true/*default*/) {
screenshotAllowed/* this is a global state of the phone */ = allowScreenshot;
showImageImpl(i);
}
}
and one like this to take screenshots
namespace os {
void takeScreenshot() /* called when 3-finger swiping, for instance */ {
if (!screenshotAllowed)
return;
takeScreenshotImpl();
}
}
This way I would assume that the messaging app, if it doesn't provide a feature akin to WhatsApp's "View Once", has a function for opening the image like this,
namespace msgapp {
void showImage(Image* i) /* called when opening any image message */ {
os::showImage(i);
}
}
whereas if does provide it (or when it is upgraded to provide it) another overload is exposed
namespace msgapp {
struct ViewOnceImage : Image {};
void showImage(ViewOnceImage* i) /* called when opening a view-once image message */ {
os::showImage(i, false);
}
}
On Android you can register a window as secure- meaning you're showing private information. This will prevent the OS from taking a screenshot or displaying the contents in the recents apps. Of course nothing stops them from taking a photo with another phone. Or using a customized OS that ignores that flag. So I wouldn't treat it as totally secure, just more likely to be secure- it takes a tiny bit of effort/inconvenience to work around. Marking it as secure is a window flag set prior to display,via
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);